2015CCPC南阳场 C - The Battle of Chibi

本文探讨了在赤壁之战背景下的一种特殊算法问题,即寻找长度为m的严格递增子序列的数量。通过动态规划结合树状数组优化,解决了在大规模数据集下快速计算这一数量的挑战。


C - The Battle of Chibi
Time Limit:4000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u

Description

Cao Cao made up a big army and was going to invade the whole South China. Yu Zhou was worried about it. He thought the only way to beat Cao Cao is to have a spy in Cao Cao's army. But all generals and soldiers of Cao Cao were loyal, it's impossible to convince any of them to betray Cao Cao. 

So there is only one way left for Yu Zhou, send someone to fake surrender Cao Cao. Gai Huang was selected for this important mission. However, Cao Cao was not easy to believe others, so Gai Huang must leak some important information to Cao Cao before surrendering. 

Yu Zhou discussed with Gai Huang and worked out   information to be leaked, in happening order. Each of the information was estimated to has   value in Cao Cao's opinion. 

Actually, if you leak information with strict increasing value could accelerate making Cao Cao believe you. So Gai Huang decided to leak exact   information with strict increasing value in happening order. In other words, Gai Huang will not change the order of the  information and just select   of them. Find out how many ways Gai Huang could do this.
 

Input

The first line of the input gives the number of test cases,   test cases follow. 

Each test case begins with two numbers   and  , indicating the number of information and number of information Gai Huang will select. Then   numbers in a line, the   number   indicates the value in Cao Cao's opinion of the   information in happening order.
 

Output

For each test case, output one line containing  Case #x: y, where   is the test case number (starting from 1) and   is the ways Gai Huang can select the information. 

The result is too large, and you need to output the result mod by  .
 

Sample Input

      
2 3 2 1 2 3 3 2 3 2 1
 

Sample Output

      
Case #1: 3 Case #2: 0

Hint

 In the first cases, Gai Huang need to leak 2 information out of 3. He could leak any 2 information as all the information value are in increasing order. In the second cases, Gai Huang has no choice as selecting any 2 information is not in increasing order. 

题意:就是给你n个数,然后找里面有多少个长度为m的严格递增子序列。

思路:这道题我们用dp去做,dp[i][j]表示以第i个数结尾长度为j的严格递增子序列有多少个。显然可以得出递推式:dp[i][j]=∑dp[x][j-1](其中1<=x<i&&a[x]<a[i])。

那么剩下的就是如何求和的问题。如果直接暴力时间复杂度为n^3,显然是不行的。所以这里要用到树状数组优化就能ac了。还要注意一个问题就是,我们用到了树状数组,为了保证肯定能累加,也就是符合上面的a[x]<a[i],我们要按照a从小到大的顺序dp并且更新树状数组。下面给代码。

#include<iostream>  
#include<stack>  
#include<cstring>  
#include<map>  
#include<string>  
#include<queue>  
#include<algorithm>  
#include<cstdio>  
#include<utility>  
using namespace std;
#define maxn 1005  
#define MOD 1000000007  
int n, m, a[maxn], dp[maxn][maxn], c[maxn][maxn], r[maxn];//c为树状数组,r数组表示a数组的元素从小到大的下标,例如r[i]=j,j为a数组里面第i个小的数的下标  
int lowbit(int x) {
	return x&-x;
}
bool cmp(int x, int y) {
	return a[x] < a[y] || (a[x] == a[y] && x>y);//两个值相等时,坐标后的优先,虽然没有这个判断也能过,但后来队友发现了,加了上去,题目并没说没有相同数据,所以我觉得还是需要加这个判断。
}
void update(int i, int j, int value) {
	while (i <= n) {
		c[i][j] += value;
		c[i][j] %= MOD;
		i += lowbit(i);
	}
}
int sum(int i, int j) {
	int sumnum = 0;
	while (i >= 1) {
		sumnum += c[i][j];
		sumnum %= MOD;
		i -= lowbit(i);
	}
	return sumnum;
}
int main() {
	int t;
	scanf("%d", &t);
	for (int tcase = 1; tcase <= t; tcase++) {
		scanf("%d%d", &n, &m);
		memset(c, 0, sizeof(c));
		for (int i = 1; i <= n; i++) {
			scanf("%d", &a[i]);
		}
		for (int i = 1; i <= n; i++)
			r[i] = i;
		sort(r + 1, r + 1 + n, cmp);
		for (int i = 1; i <= n; i++) {
			int id = r[i];
			dp[id][1] = 1;
			update(id, 1, 1);
			for (int j = 2; j <= m; j++) {
				dp[id][j] = sum(id - 1, j - 1);
				update(id, j, dp[id][j]);
			}
		}
		int ans = 0;
		for (int i = 1; i <= n; i++) {
			ans = (ans + dp[i][m]) % MOD;
		}
		printf("Case #%d: %d\n", tcase, ans);
	}
}


### CCPC 2023 H题 解析 关于CCPC 2023 H题的具体题目描述尚未公开,但从以往的比赛惯例以及类似的题目解析可以推测其可能涉及的内容和技术要点。以下是基于已有参考资料和专业知识对该类问题的解答框架。 #### 1. **问题背景** CCPC(Chinese Collegiate Programming Contest)作为国内重要的编程竞赛之一,通常会设计具有挑战性的算法问题来测试参赛者的逻辑思维能力和编码技巧。H题通常是比赛中的难点之一,往往涉及到复杂的算法模型或数据结构的应用[^2]。 #### 2. **潜在的技术方向** 根据过往的经验,H题可能会覆盖以下几个方面: - 动态规划 (Dynamic Programming)[^1] - 构造性问题 (Construction Problems)[^4] - 数学优化 (Mathematical Optimization) 假设该题属于动态规划类别,则需关注状态转移方程的设计;如果是构造性问题,则重点在于如何通过有限操作达到目标条件。 #### 3. **通用解题策略** 无论具体主题为何种类型,在面对高难度赛题时可遵循如下方法论: ##### (1)深入理解题目需求 仔细阅读并反复确认输入输出的要求及其约束条件,确保不会遗漏任何细节信息[^3]。 ##### (2)选取合适的算法工具箱 依据实际景挑选最匹配的方法论,比如当存在重叠子问题且具备最优子结构性质时优先选用DP技术[^1]。 ##### (3)编写清晰易懂的代码实现 采用模块化的方式分步完成整个功能开发流程,并辅以充分注释说明每一部分的作用机制。 ```cpp // 示例伪代码片段展示基本框架布局 #include <bits/stdc++.h> using namespace std; int main(){ ios::sync_with_stdio(false); cin.tie(0); int n; cin >> n; // 输入规模参数 vector<long long> dp(n+1, INF); // 初始化dp数组,默认极大值表示未访问过 dp[0]=0; for(int i=1;i<=n;i++){ for(auto &coin : coins){ if(i >= coin && dp[i - coin]+costs[coin]<dp[i]){ dp[i]=dp[i - coin]+costs[coin]; } } } cout << (dp[n]==INF ? -1 : dp[n])<< "\n"; } ``` 上述例子仅作示意用途,真实情况下应严格依照官方给定的数据范围调整变量类型及边界处理方式。 #### 4. **复杂度考量** 对于大规模实例而言,效率至关重要。因此除了正确率之外还需兼顾运行时间和内存消耗指标。一般建议尽可能降低渐近时间开销至O(NlogN)甚至更低级别。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值