hdu1024 dp
2015-10-26 08:12
281 查看
题意:求一个序列中的最大 m 段和,m 段不能交叉。
dp[i][0/1][j] 表示已经取完第 i 个物品,第 i 个物品取或不取,取到第 j 个子段。
用vis[i][0/1][j] 表示该 dp 值是否存在。
然后当 vis[i][0][j] 存在,即第 i 个物品不取,之前已经取了 j 个子段,可推得:
第 i+1 个不取: dp[i+1][0][j]=max(dp[i+1][0][j],dp[i][0][j]);
第 i+1 个取: dp[i+1][1][j+1]=max(dp[i+1][1][j+1],dp[i][0][j]+a[i]);
当 vis[i][1][j] 存在,即第 i 个物品取,之前已经取了 j 个子段(第 j 段可能还没有取完),可推得:
第 i+1 个不取: dp[i+1][0][j]=max(dp[i+1][0][j],dp[i][1][j]);
第 i+1 个取且放在第 j 个子段中: dp[i+1][1][j]=max(dp[i+1][1][j],dp[i][1][j]+a[i]);
第 i+1 个取且放在第 j+1 个子段中: dp[i+1][1][j+1]=max(dp[i+1][1][j+1],dp[i][1][j]+a[i]);
然后初始化 dp[1][1][1]=a[1],dp[1][0][0]=0;
由于直接开 n*2*m 会MLE,所以将第一维滚动,2*2*m 就完全没有问题,复杂度 O(n*m);
View Code
dp[i][0/1][j] 表示已经取完第 i 个物品,第 i 个物品取或不取,取到第 j 个子段。
用vis[i][0/1][j] 表示该 dp 值是否存在。
然后当 vis[i][0][j] 存在,即第 i 个物品不取,之前已经取了 j 个子段,可推得:
第 i+1 个不取: dp[i+1][0][j]=max(dp[i+1][0][j],dp[i][0][j]);
第 i+1 个取: dp[i+1][1][j+1]=max(dp[i+1][1][j+1],dp[i][0][j]+a[i]);
当 vis[i][1][j] 存在,即第 i 个物品取,之前已经取了 j 个子段(第 j 段可能还没有取完),可推得:
第 i+1 个不取: dp[i+1][0][j]=max(dp[i+1][0][j],dp[i][1][j]);
第 i+1 个取且放在第 j 个子段中: dp[i+1][1][j]=max(dp[i+1][1][j],dp[i][1][j]+a[i]);
第 i+1 个取且放在第 j+1 个子段中: dp[i+1][1][j+1]=max(dp[i+1][1][j+1],dp[i][1][j]+a[i]);
然后初始化 dp[1][1][1]=a[1],dp[1][0][0]=0;
由于直接开 n*2*m 会MLE,所以将第一维滚动,2*2*m 就完全没有问题,复杂度 O(n*m);
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; typedef long long ll; const int maxn=1e6+5; int a[maxn]; int dp[2][2][1005]; bool vis[2][2][1005]; int main(){ int m,n; while(scanf("%d%d",&m,&n)!=EOF){ for(int i=1;i<=n;++i)scanf("%d",&a[i]); memset(dp,0,sizeof(dp)); memset(vis,0,sizeof(vis)); dp[1][1][1]=a[1]; vis[1][1][1]=1; dp[1][0][0]=0; vis[1][0][0]=1; for(int k=1;k<n;++k){ int i=k&1; memset(vis[i^1],0,sizeof(vis[i^1])); for(int j=0;j<=m;++j){ if(vis[i][0][j]){ if(!vis[i^1][0][j]){ vis[i^1][0][j]=1; dp[i^1][0][j]=dp[i][0][j]; } else if(dp[i][0][j]>dp[i^1][0][j])dp[i^1][0][j]=dp[i][0][j]; if(!vis[i^1][1][j+1]){ vis[i^1][1][j+1]=1; dp[i^1][1][j+1]=dp[i][0][j]+a[k+1]; } else if(dp[i][0][j]+a[k+1]>dp[i^1][1][j+1])dp[i^1][1][j+1]=dp[i][0][j]+a[k+1]; } if(vis[i][1][j]){ if(!vis[i^1][0][j]){ vis[i^1][0][j]=1; dp[i^1][0][j]=dp[i][1][j]; } else if(dp[i][1][j]>dp[i^1][0][j])dp[i^1][0][j]=dp[i][1][j]; if(!vis[i^1][1][j]){ vis[i^1][1][j]=1; dp[i^1][1][j]=dp[i][1][j]+a[k+1]; } else if(dp[i][1][j]+a[k+1]>dp[i^1][1][j])dp[i^1][1][j]=dp[i][1][j]+a[k+1]; if(!vis[i^1][1][j+1]){ vis[i^1][1][j+1]=1; dp[i^1][1][j+1]=dp[i][1][j]+a[k+1]; } else if(vis[i^1][1][j+1]&&dp[i][1][j]+a[k+1]>dp[i^1][1][j+1])dp[i^1][1][j+1]=dp[i][1][j]+a[k+1]; } } } int ans=-0x3f3f3f3f; if(vis[n&1][1][m])ans=max(ans,dp[n&1][1][m]); if(vis[n&1][0][m])ans=max(ans,dp[n&1][0][m]); printf("%d\n",ans); } return 0; }
View Code
相关文章推荐
- 监听view添加到父控件和自己添加子控件
- 10.14~10.25刷题(shui)记录
- ds报文测试桩
- LINUX设备驱动程序的注意事项(两)建设和执行模块
- CDH(Cloudera)版本的 Hadoop
- TypeScript学习笔记(六):泛型
- awr 无法生成处理
- cin、cin.get()、getline()(讲解的很详细)黄刚的博客
- hdu1087 dp
- Linux 中 df 命令的11个例子
- Linux 中 df 命令的11个例子
- *LeetCode-4Sum
- zoj 1048 该题的要求是求出12个数字的平均数
- UI基础篇-------UITabBarController的使用
- 网上的一个helpdesk流程,将来备用
- poj 1166 The Clocks 暴力搜索
- 《算法竞赛入门经典》(第2版)第二章习题
- cell的框架结构
- TypeScript学习笔记(五):接口
- 模拟赛记录(1):10.24 T3 有趣的有趣的家庭菜园 (线段树优化DP)