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;
}

浙公网安备 33010602011771号