SDU程序设计思维与实践Week12 【HDU1024】 Max Sum Plus Plus【区间DP】

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[i1][k]}+num[j]k[i1,j1],也可能和前面的数字组合成一个分组。由于分组必须连续,所以必和前一个元素组成分组,即 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][j1]+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[i1][k]dp[i][j1]}+num[j]k[i1,j1]
  • d p [ i ] [ ∗ ] dp[i][*] dp[i][]只和 d p [ i ] [ ∗ ] dp[i][*] dp[i][] d p [ i − 1 ] [ ∗ ] dp[i-1][*] dp[i1][]有关,即当前状态之和当前状态自身和前一个状态有关,利用滚动数组优化空间性能 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][j1],dp[1t][k])+num[j]k[i1,j1]
  • 不需要知道 j − 1 j-1 j1的最大和对应的 k k k的取值,可以用 p r e [ j − 1 ] pre[j-1] pre[j1]代替 d p [ 1 − t ] [ k ] dp[1-t][k] dp[1t][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][j1],pre[j1])+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[j1]pre[j1])+num[j]
  • 在降维时,相当于处于同一个时间维度。由于 d p [ j − 1 ] dp[j-1] dp[j1]已经包含了选择 n u m [ j − 1 ] num[j-1] num[j1]的情况,因此 p r e [ j − 1 ] pre[j-1] pre[j1]不应在包含 n u m [ j − 1 ] num[j-1] num[j1]
  • 枚举时, i ≤ j i\leq j ij

代码

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

参考博文

hdu1024题解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值