您的位置:首页 > 其它

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])

最后可以用滚动数组优化内存。

代码:

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息