hdu 5542 The Battle of Chibi(2015CCPC - C题)
题目链接:hdu 5542
首届CCPC的C题,比赛时一起搞了好久,最后是队友A出的,当时有试过用树状数组来优化 dp,然后今天下午也用树状数组搞了一下午,结果还是踩了和当时一样的坑:我总是把用来记录状态的 dp 数组和树状数组里的内置数组混在一起使用了,而且两重循环的顺序也反了,以至于两组数据
3 2 3 2
1 2 3 和 3 2 1
程序跑都得出了相同的结果,无语。。。之前做 dp 和线段树结合的题时也是傻傻地分不清,说到底就是 dp 的功力很不够,所以在 dp 专场的这场比赛中除了水题外我几乎没什么贡献了,很心塞郁闷了一段时间
题目思路:先建立一个经典的 dp 模型:f[k][i] 表示长度为 k,以 b[i] 结尾的上升子序列的数量(即 dp 的状态),所以递推方程为 f[k][i] = sum{ f[k - 1][x], 1<=x< i && 1<= b[x] <= b[i]-1 },可以看到 k 只依赖于 k-1,而 i 依赖于 b[i] 前面并比 b[i] 小的(和经典的逆序数原理一样),所以可以用树状数组来快速求出,之所以写成 f[k][i] 而不是 f[i][k] 是为了方便树状数组的操作(其实调过来完全可以的,不过脑子一时间转不过弯来,树状数组一直以来都写得太死了,总是模板大法 -_-||)程序实现中还充斥着各种技巧等。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lowbit(x) ((x) & -(x))
typedef long long ll;
const int N = ;
const ll mod = ; int maxn;
ll c[N][N]; // c 数组和 maxn 是树状数组所需的数据结构
ll f[N][N]; // f[k][i] 表示长度为 k,以 b[i] 结尾的上升子序列的数量(即 dp 的状态) ll sum(int len, int x) { // 树状数组的两个函数
ll res = ;
while(x) {
res += c[len][x]; // c[][] 的 len 对应 f[][] 的 k,x 对应 f[][] 的 b[i]
if(res >= mod) res -= mod;
x -= lowbit(x);
}
return res;
} void add(int len, int x, ll v) {
while(x <= maxn) {
c[len][x] += v;
if(c[len][x] >= mod) c[len][x] -= mod;
x += lowbit(x);
}
} int b[N], a[N]; int main() {
int t,n,m,Case = ;
scanf("%d",&t);
while(t--) {
scanf("%d %d",&n,&m);
for(int i = ; i <= n; ++i) {
scanf("%d", b + i);
a[i] = b[i];
}
sort(a + , a + n + ); // 离散化
for(int i = ; i <= n; ++i)
b[i] = lower_bound(a + , a + n + , b[i]) - a; maxn = n + ;
memset(c, , sizeof c);
memset(f, , sizeof f); // 记得都要清零 ll ans = ;
// 两重循环的顺序不能搞错!
// 每次对于每个 b[i],都是已经算好了长度 1~min(i,m) 的上升子序列的数量,即 f[1~min(i,m)][i] 的值;
// 然后再到 b[i + 1];所以是先枚举 1~n 的离散化后各个元素,再枚举长度(1~min(i,m))
for(int i = ; i <= n; ++i) {
int top = min(i,m);
for(int k = ; k <= top; ++k) {
if(k == ) f[k][i] = ;
else {
f[k][i] += sum(k - , b[i] - ); // f[k][i] = sum{f[k - 1][x], 1 <= b[x] <= b[i]-1 }
if(f[k][i] >= mod) f[k][i] -= mod;
}
add(k, b[i], f[k][i]); // 把算好的 f[k][i] 更新进树状数组中去
}
ans += f[m][i]; // 这时候 f[m][i] 已经算好了,所以加入到答案中
if(ans >= mod) ans -= mod;
}
printf("Case #%d: %I64d\n", ++Case, ans);
}
return ;
}
二重循环中,先固定 i,然后枚举 k,颠倒过来是不行的,原因是如果先固定 k 而枚举 i 的话那么计算完 k-1 后,1~n 的元素都已经进入树状数组中去了,也就是在计算 i 时,i 后面的元素都已经进入树状数组中,这样子就混淆了之前的元素,就好像求逆序数时必须从前往后按顺序来,否则后面比前面的先插入到树状数组中就没意义了。
dp 数组记录状态,然后更新进相应的数据结构中,和 hdu 4521 小明系列问题——小明序列 有相似之处,必须好好体会下 dp 和数据结构结合的这种思想与处理方式。
hdu 5542 The Battle of Chibi(2015CCPC - C题)的更多相关文章
- HDU - 5542 The Battle of Chibi(LIS+树状数组优化)
The Battle of Chibi Cao Cao made up a big army and was going to invade the whole South China. Yu Zho ...
- HDU 5542 - The Battle of Chibi - [离散化+树状数组优化DP]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5542 Problem DescriptionCao Cao made up a big army an ...
- 【树状数组+dp】HDU 5542 The Battle of Chibi
http://acm.hdu.edu.cn/showproblem.php?pid=5542 [题意] 给定长为n的序列,问有多少个长为m的严格上升子序列? [思路] dp[i][j]表示以a[i]结 ...
- [HDU 5542] The Battle of Chibi
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5542 [算法] 树状数组优化DP [代码] #include<bits/stdc++.h&g ...
- HDOJ 5542 The Battle of Chibi
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题目大意:在n个数中找长度为m的单调上升子序列有多少种方案 题目思路:DP,离散化,树状数组优化 ...
- The 2015 China Collegiate Programming Contest C. The Battle of Chibi hdu 5542
The Battle of Chibi Time Limit: 6000/4000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Othe ...
- 2015南阳CCPC C - The Battle of Chibi DP
C - The Battle of Chibi Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 无 Description Cao Cao made up a ...
- hdu5542 The Battle of Chibi【树状数组】【离散化】
The Battle of Chibi Time Limit: 6000/4000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Othe ...
- CDOJ 1217 The Battle of Chibi
The Battle of Chibi Time Limit: 6000/4000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Othe ...
随机推荐
- 执行带参数的sql字符串
--要传入的参数 declare @Rv NVARCHAR(40) --要执行的带参数的sql字符串 declare @sql nvarchar(max) set @sql='select * fr ...
- Java学习-044-文件拷贝
不用说了,又是一个经常用到的方法,直接上码了...敬请各位小主参阅!若有不足,敬请指正,非常感谢! 文件拷贝源码: /** * <strong>文件拷贝</strong>< ...
- js 除法 取整
js 除法 取整 1.丢弃小数部分,保留整数部分 js:parseInt(7/2) 2.向上取整,有小数就整数部分加1 js: Math.ceil(7/2) 3,四舍五入. js: Math.roun ...
- javascript源代码学习之五——jQuery.deferred
jQuery.Defered——异步队列用于管理一组回调函数(成功resolve,失败reject,消息progress),基于上一节实现的jQuery.callbacks完成. done,fail, ...
- Android 通过 Wifi 调试 Debug (Android Studio)
参考资料: http://www.cnblogs.com/sunzhenxing19860608/archive/2011/07/14/2106492.html 前提: Android 手机 和 PC ...
- Silverlight TreeView 动态绑定Xml 文件
随着应用程序的不断升级,客户的需求不断增多,程序员不得不对自己的应用程序做出相应的修改,如果修改的内容较多,那么就必须找出一种简便方法,下面就为大家介绍一下在SilverLight 中左边导航栏T ...
- 向ES6看齐,用更好的JavaScript(二)
本文是ES6系列的第二篇,主要介绍ES6中对现有对象方法属性的拓展,先上传送门: 1 变量部分 2 现有对象拓展 3 新增数据类型/数据结构 4 新的异步编程模式 5 类和模块 1 增加了模板字符串 ...
- Android – 学习操作NFC – 2
在<Android – 学习操作NFC – 1>说明了Android在处理NFC tag的机制.tag dispatch system的运作流程,以及三种ACTION_NDEF_DISCO ...
- mfc ui库
引用:http://blog.csdn.net/weiqubo/article/details/6783717 Xtrme toolkit,BCGControlBar,SkinMagic,AppFac ...
- POJ - 1978 Hanafuda Shuffle
最初给牌编号时,编号的顺序是从下到上:洗牌时,认牌的顺序是从上到下.注意使用循环是尽量统一“i”的初始化值,都为“0”或者都为“1”,限界条件统一使用“<”或者“<=”. POJ - 19 ...