题意:输入m和n,给出一个n长数字序列。问m个不交叉连续段之和最大为多少。
题解:
dp[i][j]表示前j个序列数字,找出i段,且a[j]包含在段内时,最大的和。则:
dp[i][j]=max(dp[i][j-1]+a[j],max(dp[i-1][k])+a[j])(0<k<j);
由于如果用c[j-1]=max(dp[i-1][k]),那么max(dp[i][k])=max(c[j-1],dp[i][j-1])。从而dp[i][j]只与前一行和本行前面的数有关,继而得到
dp[j]=max(dp[j-1]+a[j],c[j-1]+a[j]);//dp[j-1]已经被更新过,相当于dp[i][j-1],而c[j-1]在这之前不能被更新,之后立马更新
代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1e6+10;
const int INF=1e8;
int dp[maxn];
int a[maxn];
int c[maxn];
int main()
{
int m,n;
while(scanf("%d%d",&m,&n)!=EOF)
{
int i,j,k,ans;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
c[i]=dp[i]=0;
}
c[0]=dp[0]=0;
for(i=1;i<=m;i++)
{
ans=-INF;
for(j=i;j<=n;j++)
{
dp[j]=max(dp[j-1]+a[j],c[j-1]+a[j]);
c[j-1]=ans;
ans=max(ans,dp[j]);
}
}
printf("%d\n",ans);
}
return 0;
}