hdu5125 树状数组+dp
2015-08-01 23:33
288 查看
hdu5125 他说的是n个人每个人都有两个气球a,b,气球各自都有相应的体积,现在让他们按照序号排列好来,对他们的a气球体积值计算最长上升子序列,对于这整个排列来说有m次机会让你将a气球替换成b气球(允许不使用完),问最后的最长上升子序列 的长度是多少,哈哈,当然用dp的思想我们很容易就能知道状态的转移 dp[1000][1000][2],但是苦于状态转移的复杂度太大了达到了 n*n*m肯定受不了,那好我们可以列出这个方程的转移方法
(0表示a气球1为b气球)
dp[i][j][0]=max( dp[k][j][0] +1(a[k]<a[i]) , dp[k][j][j] +1(b[k]<a[i]) )0<=k<i
dp[i][j][1]=max( dp[k][j-1][0] +1(a[k]<b[i]) , dp[k][j-1][1] +1(b[k]<b[i]) )0<=k<i
想想优化方法 看来还是需要有换个想法的能力 啊 !
通过建立m棵树状数组 第j棵树 表示 使用了 j 个 能 量 的 时 候 每个位置所能到达的最高点,说清楚一点就是讲这n*2个气球体积进行离散,得到了树状数组的每个节点从第0个人枚举到第n-1个,比如到达了第i个人 那么 到达他时使用了j个机会的 方案是不是 就是去找比ai(假设离散后在k这个位置)小的那些气球使用j个机会时达到的最长序列加1呢,好那么现就使用树状数组去计算出前k-1 项的 最大值S,然后将S这个值插入当前这个树状数组中 ,那么现在 我们考虑使用b气球可以去j-1 这棵树上去找 然后得到的值加1 插入第j棵树上,哇这样很完美啊! 瞬间将复杂度减了2个0,这样一直不断地做下去直到结束.
View Code
(0表示a气球1为b气球)
dp[i][j][0]=max( dp[k][j][0] +1(a[k]<a[i]) , dp[k][j][j] +1(b[k]<a[i]) )0<=k<i
dp[i][j][1]=max( dp[k][j-1][0] +1(a[k]<b[i]) , dp[k][j-1][1] +1(b[k]<b[i]) )0<=k<i
想想优化方法 看来还是需要有换个想法的能力 啊 !
通过建立m棵树状数组 第j棵树 表示 使用了 j 个 能 量 的 时 候 每个位置所能到达的最高点,说清楚一点就是讲这n*2个气球体积进行离散,得到了树状数组的每个节点从第0个人枚举到第n-1个,比如到达了第i个人 那么 到达他时使用了j个机会的 方案是不是 就是去找比ai(假设离散后在k这个位置)小的那些气球使用j个机会时达到的最长序列加1呢,好那么现就使用树状数组去计算出前k-1 项的 最大值S,然后将S这个值插入当前这个树状数组中 ,那么现在 我们考虑使用b气球可以去j-1 这棵树上去找 然后得到的值加1 插入第j棵树上,哇这样很完美啊! 瞬间将复杂度减了2个0,这样一直不断地做下去直到结束.
#include <iostream> #include <cstdio> #include <algorithm> #include <string.h> using namespace std; const int maxn=1005; int a[maxn],b[maxn]; int c[maxn][maxn*2],h[maxn*2],L; int lowbit(int x){ return x&(-x); } void add(int loc, int floor,int v){ while(loc<=L){ c[floor][loc]=max(v,c[floor][loc]); loc+=lowbit(loc); } } int sum(int loc, int floor){ int ans=0; while(loc>0){ ans=max(c[floor][loc],ans); loc-=lowbit(loc); } return ans; } int main() { int cas; scanf("%d",&cas); while(cas--){ int n,m; scanf("%d%d",&n,&m); L=0; for(int i=0; i<n; ++i){ scanf("%d%d",&a[i],&b[i]); h[L++]=a[i]; h[L++]=b[i]; } memset(c,0,sizeof(c)); sort(h,h+L); L=unique(h,h+L)-h; int ans=1; for(int i=0; i<n; ++i){ int loca = lower_bound(h,h+L,a[i])-h+1; int locb = lower_bound(h,h+L,b[i])-h+1; int val; for(int j=min(i+1,m);j>0; j--){ val = sum(loca-1,j); ans=max(ans,val+1); add(loca,j,val+1); val = sum(locb-1,j-1); ans=max(ans,val+1); add(locb,j,val+1); } val = sum(loca-1,0); ans=max(ans,val+1); add(loca,0,val+1); } printf("%d\n",ans); } return 0; }
View Code
相关文章推荐
- 师大校赛D coloring Game 并查集
- MYSQL用户管理
- 信号槽
- (5) 中文处理专题
- Fence Repair
- system.exit(0)和system.exit(1)区别
- 莫队算法
- iptables WEB服务器配置示例
- 一个Netfilter nf_conntrack流表查找的优化-为conntrack增加一个per cpu cache
- chardet字符集检测模块
- !HDU 4334 集合各出一数和为0是否存在-思维、卡时间-(指针的妙用)
- hdu1999 可以筛法做
- 设计模式之工厂方法模式
- 算法学习之旅
- 6.1 守护进程课后题2015/8/1
- 最长回文子串
- Scala深入浅出实战经典-1
- Spark源码阅读笔记之BlockObjectWriter
- Android异步之Asynctask与Handler你所应该知道的一切
- 扩展kmp 模板