Max Sum Plus Plus
Problem Description
Now I think you have got an AC in Ignatius.L’s “Max Sum” problem. To be a brave ACMer, we always challenge ourselves to more difficult problems. Now you are faced with a more difficult problem.
Given a consecutive number sequence S1, S2, S3, S4 … Sx, … Sn (1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ Sx ≤ 32767). We define a function sum(i, j) = Si + … + Sj (1 ≤ i ≤ j ≤ n).
Now given an integer m (m > 0), your task is to find m pairs of i and j which make sum(i1, j1) + sum(i2, j2) + sum(i3, j3) + … + sum(im, jm) maximal (ix ≤ iy ≤ jx or ix ≤ jy ≤ jx is not allowed).
But I`m lazy, I don’t want to write a special-judge module, so you don’t have to output m pairs of i and j, just output the maximal summation of sum(ix, jx)(1 ≤ x ≤ m) instead. ^ _ ^
Input
Each test case will begin with two integers m and n, followed by n integers S1, S2, S3 … Sn.
Process to the end of file.
output
Output the maximal summation described above in one line.
Sample Input
1 3 1 2 3
2 6 -1 4 -2 3 -2 3
Sample Output
6
8
Hint
Huge input, scanf and dynamic programming is recommended.
思路分析
- d p [ i ] [ j ] dp[i][j] dp[i][j]表示在选取第 j j j个数字的情况下,将前 j j j个数字分成 i i i组的最大和。
- 对于第 j j j个数字,可能自己单独作为一个新分组,此时 d p [ i ] [ j ] = m a x { d p [ i − 1 ] [ k ] } + n u m [ j ] , k ∈ [ i − 1 , j − 1 ] dp[i][j]=max\{dp[i-1][k]\}+num[j],k\in[i-1,j-1] dp[i][j]=max{dp[i−1][k]}+num[j],k∈[i−1,j−1],也可能和前面的数字组合成一个分组。由于分组必须连续,所以必和前一个元素组成分组,即 d p [ i ] [ j ] = d p [ i ] [ j − 1 ] + n u m [ j ] dp[i][j]=dp[i][j-1]+num[j] dp[i][j]=dp[i][j−1]+num[j].
- 由此即可得到 d p [ i ] [ j ] = m a x { d p [ i − 1 ] [ k ] , d p [ i ] [ j − 1 ] } + n u m [ j ] , k ∈ [ i − 1 , j − 1 ] dp[i][j]=max\{dp[i-1][k],dp[i][j-1]\}+num[j],k\in[i-1,j-1] dp[i][j]=max{dp[i−1][k],dp[i][j−1]}+num[j],k∈[i−1,j−1]
- d p [ i ] [ ∗ ] dp[i][*] dp[i][∗]只和 d p [ i ] [ ∗ ] dp[i][*] dp[i][∗]和 d p [ i − 1 ] [ ∗ ] dp[i-1][*] dp[i−1][∗]有关,即当前状态之和当前状态自身和前一个状态有关,利用滚动数组优化空间性能 d p [ t ] [ j ] = m a x ( d p [ t ] [ j − 1 ] , d p [ 1 − t ] [ k ] ) + n u m [ j ] , k ∈ [ i − 1 , j − 1 ] dp[t][j]=max(dp[t][j-1],dp[1-t][k])+num[j],k\in[i-1,j-1] dp[t][j]=max(dp[t][j−1],dp[1−t][k])+num[j],k∈[i−1,j−1]
- 不需要知道 j − 1 j-1 j−1的最大和对应的 k k k的取值,可以用 p r e [ j − 1 ] pre[j-1] pre[j−1]代替 d p [ 1 − t ] [ k ] dp[1-t][k] dp[1−t][k],即 d p [ t ] [ j ] = m a x ( d p [ t ] [ j − 1 ] , p r e [ j − 1 ] ) + n u m [ j ] dp[t][j]=max(dp[t][j-1],pre[j-1])+num[j] dp[t][j]=max(dp[t][j−1],pre[j−1])+num[j],由此可将第一维度省去,优化为 d p [ j ] = m a x ( d p [ j − 1 ] , p r e [ j − 1 ] ) + n u m [ j ] dp[j]=max(dp[j-1],pre[j-1])+num[j] dp[j]=max(dp[j−1],pre[j−1])+num[j]
- 在降维时,相当于处于同一个时间维度。由于 d p [ j − 1 ] dp[j-1] dp[j−1]已经包含了选择 n u m [ j − 1 ] num[j-1] num[j−1]的情况,因此 p r e [ j − 1 ] pre[j-1] pre[j−1]不应在包含 n u m [ j − 1 ] num[j-1] num[j−1]
- 枚举时, i ≤ j i\leq j i≤j
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int inf=1e8;
int m,n,a[1000010],dp[1000010],pre[1000010],temp;
int main(){
while(scanf("%d%d",&m,&n)!=EOF){
memset(dp,0,sizeof dp);
memset(pre,0,sizeof pre);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=m;i++){
temp=-inf;
for(int j=i;j<=n;j++){
dp[j]=max(dp[j-1],pre[j-1])+a[j];
pre[j-1]=temp;
temp=max(temp,dp[j]);
}
}
cout<<temp<<endl;
}
}