hdu1024 最大m子串和

1024

题意:给一个长度为n的序列,找出m个不相交子串的和的最大值

思路:dp[i][j]表示取第j个数,并且前j个数分成i个区间的最大值,状态转移方程为 dp[i][j]=max(dp[i][j-1]+a[j], dp[i-1][k]+a[j])(k=i-1 i i+1 ... j-1 ),dp[i][j-1]+a[j]表示前j-1个分成i个区间并且取了a[j-1],那么在a[j]取的情况下,区间数没有增加,dp[i-1][k]表示在由i-1个区间组成的答案中加入a[j],区间数+1,这里注意一点,状态转移的时候j是从j=i开始遍历的,所以就会出现一个状态 dp[i][i-1] ,这是不可能的,要初始化为-inf,然后就是时间和空间上面的优化了,空间上面,由于每次dp状态只与上一个状态有关,所以可以用滚动数组优化,空间上对k这一维进行优化,从状态转移方程不难看出dp[i-1][k]是在找上一个状态中第二维范围为i-1到j-1的最大值,这里可以每次处理出O(1)求最大值

AC代码: 

#include "iostream"
#include "iomanip"
#include "string.h"
#include "stack"
#include "queue"
#include "string"
#include "vector"
#include "set"
#include "map"
#include "algorithm"
#include "stdio.h"
#include "math.h"
#pragma comment(linker, "/STACK:102400000,102400000")
#define bug(x) cout<<x<<" "<<"UUUUU"<<endl;
#define mem(a,x) memset(a,x,sizeof(a))
#define step(x) fixed<< setprecision(x)<<
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define ll long long
#define endl ("
")
#define ft first
#define sd second
#define lrt (rt<<1)
#define rrt (rt<<1|1)
using namespace std;
const ll mod=1e9+7;
const ll INF = 1e18+1LL;
const int inf = 1e9+1e8;
const double PI=acos(-1.0);
const int N=1e6+100;

///d[i][j]表示在选取第j个数字的情况下,将前j个数字分成i组的最大和
int dp[2][N],a[N],pre[N],n,m;
int main(){
    while(scanf("%d%d",&m,&n)==2){
        for(int i=1; i<=n; ++i){
            scanf("%d",&a[i]);
        }
        int ans=-inf; mem(pre,0), mem(dp,0);
        for(int i=1,cur=1; i<=m; ++i,cur^=1){
            for(int j=i,tmp=-inf; j<=n; ++j){
                dp[cur][i-1]=-inf;
                dp[cur][j]=max(dp[cur][j-1]+a[j],pre[j-1]+a[j]);
                pre[j-1]=tmp;
                tmp=max(tmp,dp[cur][j]);
                if(i==m) ans=max(ans,dp[cur][j]);
            }
            /*for(int j=i,tmp=-inf; j<=n; ++j){
                tmp=max(tmp,dp[cur][j]);
                pre[j]=tmp;
            }*/
        }
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/max88888888/p/7668275.html