题意还是很简单的,就是给你n个数,把他分成m个独立的区间,要求所有区间的和最大
那么我们很容易想到递推方程
dp[j][i]表示前j个数分成i个区间的最大和且以a[j]结尾
递推方程就为dp[j][i]=max(dp[j-1][i]+a[j],max(dp[t][i-1]+a[j])) (i-1<=t<=j)
可以看到我们这个方程的时间复杂度为 m×n×n,因为n=1e6所以时间复杂度炸了
然后我们发现dp[j][i]只与dp[j-1][i],和dp[*][i-1]的最大值有关
那么我们在求i-1的时候保留最大值就好了呀
这就成功的把时间复杂度降到m×n了
接下来正片开始
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
#define maxn 1001000
using namespace std;
long long dp[maxn],num[maxn],mmax[maxn],sum[maxn];
int main()
{
int m,n;
long long mmmax;
while(~scanf("%d %d",&m,&n))
{
sum[0]=0;
for (int k=1;k<=n;k++)
{
scanf("%lld",&num[k]);
mmax[k]=0;
dp[k]=0;
}
dp[0]=0;
mmax[0]=0;//初始化是全部设为0 //因为对于第一个dp[1]他要用到的是dp【0】和mmax【0】嘛 //然后对于i=1时的每一个dp【j】他前面就是相当于max(dp【j-1】【0】)取0的话当然是0咯
for (int i=1;i<=m;i++)
{
mmmax=-0x3f3f3f3f;
for (int j=i;j<=n;j++)
{
dp[j]=max(dp[j-1]+num[j],mmax[j-1]+num[j]); //原来的方程是dp[j][i]=max(dp[j-1][i]+a[j],max(dp[t][i-1]+a[j])) (i-1<=t<=j) //dp[j]=dp[j][i] mmax[j-1]=max(dp[t][i-1]) 0<=t<=j-1
mmax[j-1]=mmmax;//这个mmax[j-1]是给下一个i用的哦
mmmax=max(mmmax,dp[j]);//然后我们更新mmmax的值,就是dp[i]到dp[j]的最大值
}
}
printf("%lld\n",mmmax);//注意不是输出dp[n]哦,因为dp[n]是以n结尾的
}
return 0;
}
本文介绍了一个经典的区间划分问题,通过动态规划求解最优解,并采用一种优化策略将时间复杂度从O(m*n^2)降低到O(m*n)。文章提供了完整的C++代码实现。
1233

被折叠的 条评论
为什么被折叠?



