51NOD1052 最大M字段和

传送门

分析

一眼看去我们自然会想到dp[i][j][k]表示区间[i,j]中选k个子段的最大值。然后我们考虑降去一维。我们设dp[i][j]表示考虑了前i个数,在选了a[i]的情况下共有j个子段的最大值,于是可以列出转移方程式dp[i][j]=Max{dp[i-1][j],Max{dp[k][j-1](k<i)}}+a[i],但是我们发现空间和时间都会爆炸,空间问题我们可以用滚动数组来进行解决,而对于时间问题我们可以记录一个dpmax[i][j]表示Max{dp[k][j](k<=i)}的值,注意这个dpmax数组同样也要滚动,于是我们就可以将转移复杂度变到O(1),在适当剪枝就可以AC啦。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
long long dp[2][6000],dpmax[2][6000],a[6000],cnt,sum;
int main(){
      long long n,m,i,j,k;
      scanf("%lld%lld",&n,&m);
      for(i=1;i<=n;i++)scanf("%lld",&a[i]);
      long long now=0;
      for(i=1;i<=n;i++){
          now^=1;
          memset(dp[now],0,sizeof(dp[now]));
          for(j=1;j<=min(i,m);j++){
            dp[now][j]=max(dp[now^1][j],dpmax[now^1][j-1]);
            dp[now][j]+=a[i];
            dpmax[now][j]=max(dp[now][j],dpmax[now^1][j]);
          }
      }
      printf("%lld
",dpmax[now][m]);
      return 0;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/9692806.html