Max Sum Plus Plus HDU - 1024 (DP+滚动数组优化)

题意:
n个点,求出m对不相交连续子序列的最大和。

思路:

状态:\(dp[i][j]\) 表示前j个数组组成了i个不相交区间的最大和。
转移:
第j个数只有两个状态:

  • 和别的数组成了一个区间
    那么\(dp[i][j] = dp[i][j - 1] + num[j]\)

  • 自己独立成了一个区间
    那么\(dp[i][j] = dp[i - 1][k] + num[j]\)
    其中的\(dp[i-1][k] = max(dp[i-1][i - 2], dp[i-1][i - 1] … dp[i-1][j-1])\)

综上
\(dp[i][j] = max(dp[i][j - 1], dp[i - 1][k]) + num[j]\)

其中dp[i-1][k]可以用一个变量纪录下来,纪录所求的每个dp[i-1][k]的最大值
优化:
因为每个dp只和上一个有关,所以就可以化成滚动数组求解了

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
using namespace std;
const int N = 1e6+ 10;
#define int long long 
int n,m;
int a[N];
int dp[2][N];//分成i个块,在前j个选。
int premax[N];
signed main()
{
    while(~scanf("%lld %lld",&n,&m)){
        for(int i=1;i<=m;i++){
            scanf("%lld",&a[i]);
        }

        memset(dp,0,sizeof dp);
        memset(premax,0,sizeof premax);

        int maxn=-1e9;
        for(int i=1;i<=n;i++){
            maxn=-1e9;
            for(int j=i;j<=m;j++){
                //此时premax是上一层的最大值
                dp[i&1][j]=max(dp[i&1][j-1]+a[j],premax[j-1]+a[j]);
                //更新为本层的premax
                premax[j-1]=maxn;
                //更新本层前j的dp最大值
                maxn=max(maxn,dp[i&1][j]);
            }
        }
        printf("%lld\n",maxn);//因为最优解一定是分为n块,所以最后一层的maxn就是答案。
        }
    return 0;
}
posted @ 2022-09-30 21:08  kingwzun  阅读(35)  评论(0)    收藏  举报