51Nod 1052 思维 + 动态规划
2017-12-15 23:33
225 查看
题目链接
题意:
将n个数划分成不超过m个不相交的子段,问子段和最大可以为多少?
思路:
设dp[i][j]为前i个数划分成不超过j个不相交子段的最大和。
显然有:
dp[i][j]=max(dp[i−1][j],max(dp[k−1][j−1]+sum[i]−sum[k−1])(1<=k<=i))
很明显这是一个O(n2m)的复杂度,不可承受。
考虑优化。
之前一直在想数据结构方面的优化,但一直没有什么进展。
故考虑内部k的循环是否也可以用DP来维护。
设g[i][j]=max(dp[k−1][j−1]−sum[k−1])(1<=k<=i)
观察易得:
g[i][j]=max(g[i−1][j],dp[i−1][j−1]−sum[i−1])
故最终有:
dp[i][j]=max(dp[i−1][j],g[i][j]+sum[i])
最后可以用滚动数组优化内存。
代码:
题意:
将n个数划分成不超过m个不相交的子段,问子段和最大可以为多少?
思路:
设dp[i][j]为前i个数划分成不超过j个不相交子段的最大和。
显然有:
dp[i][j]=max(dp[i−1][j],max(dp[k−1][j−1]+sum[i]−sum[k−1])(1<=k<=i))
很明显这是一个O(n2m)的复杂度,不可承受。
考虑优化。
之前一直在想数据结构方面的优化,但一直没有什么进展。
故考虑内部k的循环是否也可以用DP来维护。
设g[i][j]=max(dp[k−1][j−1]−sum[k−1])(1<=k<=i)
观察易得:
g[i][j]=max(g[i−1][j],dp[i−1][j−1]−sum[i−1])
故最终有:
dp[i][j]=max(dp[i−1][j],g[i][j]+sum[i])
最后可以用滚动数组优化内存。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int A = 5000 + 10; ll dp[2][A],g[2][A],sum[A]; int main(){ //freopen("output","w",stdout); int n,m; scanf("%d%d",&n,&m); sum[0] = 0; for(int i=1 ;i<=n ;i++){ ll x; scanf("%I64d",&x); sum[i] = sum[i-1] + x; } for(int i=1 ;i<=n ;i++){ for(int j=1 ;j<=m ;j++){ g[i&1][j] = max(g[(i-1)&1][j],dp[(i-1)&1][j-1] - sum[i-1]); dp[i&1][j] = max(dp[i&1][j],dp[(i-1)&1][j]); dp[i&1][j] = max(dp[i&1][j],g[i&1][j] + sum[i]); } } printf("%I64d\n",dp[n&1][m]); return 0; }
相关文章推荐
- 51nod 1241 特殊的排序(锻炼思维的好题)
- 51nod 1052最大M子段和 & poj 2479最大两子段和
- 51nod 1006 最长公共子序列Lcs(经典动态规划)
- 51Nod 1052/1053/1115 最大M子段和V1/V2/V3
- 51nod 1449 砝码称重(思维+进制)
- 【51nod】--1138 连续整数的和 (思维)
- 51nod 1548 欧姆诺姆和糖果【思维+分类讨论】
- 【51nod 教程】矩阵取数问题(动态规划)
- 51nod 1433 0和5 【思维题】
- 51nod 1279 扔盘子(思维题)
- 51nod 1799 二分答案 思维 + 分块打表
- Codeforces 458A/51nod 1491 黄金系统【思维】好题~
- 20140914 【 动态规划 】 51nod 1183 . 编辑距离
- 51Nod 1335 思维
- 51nod 1052 最大M子段和
- 51nod 动态规划基础
- 51nod 1021 石子归并 -动态规划
- 51nod 1050 循环数组最大子段和(思维)
- 51nod 1201 整数划分(锻炼思维的好题)
- 51Nod - 1413 -权势二进制 (思维题)