HDU1024 Max Sum Plus Plus

来源:互联网 发布:日本中国夏令营知乎 编辑:程序博客网 时间:2024/05/16 09:54


Max Sum Plus Plus

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 24256    Accepted Submission(s): 8313


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 32 6 -1 4 -2 3 -2 3
 

Sample Output
68
Hint
Huge input, scanf and dynamic programming is recommended.
 

Author
JGShining(极光炫影)
 

题意:给定n个数,求不相交的m段连续子序列最大和。

思路:用dp[i][j]表示将j个数字分成i段,并且最后一段以numb[j]结尾的最大和,那么dp[i][j]的来源情况只有两种:

1.将前j-1个数分成i段,然后把这个数直接接在最后一段,那么dp[i][j] = dp[i][j-1] + numb[j].

2.将前j-1个数分成i-1段,然后再将第j个数变成独立的一段 那么dp[i][j] = max(dp[i-1][k])(i-1<=k<j)

综上可以得到转移方程:dp[i][j] = max( dp[i][j-1] + numb[j],  max(dp[i-1][k])(i-1<=k<j) )

但是n的范围是1e6,显然开二维数组是不行的,需要优化一下。

优化:发现dp[i][j] 之和dp[i][j-1]以及dp[i-1][k]有关,我们可以用一个一维数组,每次滚动记录dp[i][j].

但是这样的话,寻找max(dp[i-1][k])还需要遍历一遍,显然是不合理的,所以我们再开一个数组pre[j]记录max(dp[i-1][k])(i-1<=k<j).

这样我们便可以每次直接读取这个值即可。

#include <vector>#include <map>#include <set>#include <queue>#include <stack>#include <algorithm>#include <sstream>#include <iostream>#include <cstdio>#include <cmath>#include <cstdlib>#include <cstring>#include <string>#if defined(_MSC_VER) || __cplusplus > 199711L#define aut(r,v) auto r = (v)#else#define aut(r,v) __typeof(v) r = (v)#endif#define each(it,o) for(aut(it, (o).begin()); it != (o).end(); ++ it)#define fur(i,a,b) for(int i=(a);i<=(b);i++)#define furr(i,a,b) for(int i=(a);i>=(b);i--)#define cl(a) memset((a),0,sizeof(a))#define mp make_pair#define pb push_back#define fi first#define se second#define sc(x) scanf("%d",&x)using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair <int, int> pii;const int inf=0x3f3f3f3f;const double eps=1e-8;const int mod=1000000007;const double pi=acos(-1);inline void gn(long long&x){    int sg=1;char c;while(((c=getchar())<'0'||c>'9')&&c!='-');c=='-'?(sg=-1,x=0):(x=c-'0');    while((c=getchar())>='0'&&c<='9')x=x*10+c-'0';x*=sg;}inline void gn(int&x){long long t;gn(t);x=t;}inline void gn(unsigned long long&x){long long t;gn(t);x=t;}inline void gn(double&x){double t;scanf("%lf",&t);x=t;}inline void gn(long double&x){double t;scanf("%lf",&t);x=t;}int gcd(int a,int b){return a? gcd(b%a,a):b;}ll powmod(ll a,ll x,ll mod){ll t=1ll;while(x){if(x&1)t=t*a%mod;a=a*a%mod;x>>=1;}return t;}// (づ°ω°)づe★int numb[1000005];int dp[1000005];int pre[1000005];void init(){    cl(dp);    cl(pre);}int n,m; int main(){    int tmp;    while(~scanf("%d %d",&m,&n)){        init();        fur(i,1,n)gn(numb[i]);        fur(i,1,m){             tmp = -inf;                 fur(j,i,n){                        dp[j] = max(dp[j-1],pre[j-1]) + numb[j];                pre[j-1] = tmp;         //因为计算到dp[j]的时候 ,需要用到pre[j-1]                 tmp = max(dp[j],tmp);    //所以我们不能在获得dp[j-1]的时候立刻更新pre[j-1]            }                            //而是先临时保存一下这个值        }                                //当计算完dp[j]以后再修改dp[j-1];         printf("%d\n",tmp);            //因为最大的值不一定是以numb[n]结尾的     }                                //所以不能输出 dp[n] 而是应该输出dn[i]里面最大的那个     return 0;}


0 0