hdu 1024(dp)

 

传送门:Max Sum Plus Plus

题意:从n个数中选出m段不相交的连续子段,求这个和最大。

分析:经典dp,dp[i][j][0]表示不取第i个数且前i个数分成j段达到的最优值,dp[i][j][1]表示取了第i个数且前i个数分成j段达到的最优值。

那么有:

dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]).

dp[i][j][1]=max(dp[i-1][j-1][0]+a[i],max(dp[i-1][j-1][1],dp[i][j][1])+a[i])).

红色部分略坑,仔细体会一下,因为连续的一段可能拆成多一段刚好符合m段到达最好,不一定得选一段连续的子系列只当成一段最好,可能分成多段更优。

由于n过大,使用滚动数组优化空间。

#include <algorithm>
#include <cstdio>
#include <cstring>
#define N 1000010
#define inf 0x3f3f3f3f
using namespace std;
int dp[2][N][2],a[N];
int n,m;
int main()
{
    while(scanf("%d%d",&m,&n)>0)
    {
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for (int i = 0; i <= m; i++) {
            dp[0][i][0] = dp[1][i][0] = dp[0][i][1] = dp[1][i][1] = -inf;
        }
        dp[0][0][0]=dp[0][0][1]=0;
        for(int i=1,t=1;i<=n;i++,t=!t)
        {
            for(int j=0;j<=i&&j<=m;j++)
            {
                dp[t][j][0]=max(dp[!t][j][0],dp[!t][j][1]);
                if(j)dp[t][j][1]=max(dp[!t][j-1][0]+a[i],max(dp[!t][j][1],dp[!t][j-1][1])+a[i]);
            }
        }
        printf("%d\n",max(dp[n&1][m][0],dp[n&1][m][1]));
    }
}
View Code

 

posted on 2015-03-10 23:24  lienus  阅读(150)  评论(0编辑  收藏  举报

导航