HDU 1024 Max Sum Plus Plus【DP+滚动数组】

来源:互联网 发布:牵引变电所接地网优化 编辑:程序博客网 时间:2024/05/18 08:50

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 S 1, S 2, S 3, S 4 … S x, … S n (1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ S x ≤ 32767). We define a function sum(i, j) = S i + … + S j (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(i 1, j 1) + sum(i 2, j 2) + sum(i 3, j 3) + … + sum(i m, j m) maximal (i x ≤ i y ≤ j x or i x ≤ j y ≤ j x 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(i x, j x)(1 ≤ x ≤ m) instead. ^_^
Input
Each test case will begin with two integers m and n, followed by n integers S 1, S 2, S 3 … S n.
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.

题意:最大和连续子序列的增强版,要求从一序列中取出若干段,这些段之间不能交叉,使得和最大并输出。

各种分析:这个题太难了,空间容易炸,时间也容易炸。

然而,我们可以通过滚动数组同时解决时空的限制!
时间降一级,空间降一维。
就这么个“破”东西,搞了三个小时!
具体的都注释在代码上了。

PS:给出的两个神犇的blog,个人觉得在解释方面出现了小小的笔误,还望大家留意!我某鱼的不严谨或是错误的地方,也还请大家多多指教!

#include<iostream>#include<cstring>#include<algorithm>#include<vector>using namespace std;//http://www.cnblogs.com/jiangjing/archive/2013/07/25/3214729.html 这个前辈写得很棒!//http://www.cnblogs.com/kuangbin/archive/2011/08/04/2127085.html#define Irish_Moonshine main#define LL long long int#define INF 0x7fffffffconst int maxn = 1e6 + 10;short int a[maxn];int dp[maxn];int get_max[maxn];//滚动数组int Irish_Moonshine(){    int m, n;    while (~scanf("%d%d", &m, &n))    {        memset(dp, 0, sizeof(dp));        memset(get_max, 0, sizeof(get_max));        for (int i = 1; i <= n; i++)        {            scanf("%d", &a[i]);        }        dp[0] = get_max[0] = 0;        int Max = -INF;        for (int i = 1; i <= m; i++)//跑分成的段数        {            Max = -INF;            for (int j = i; j <= n; j++)//跑前j个数分成i段的最大值            {                //第i段显然是在i及其之后了~,从i开始枚举就可                dp[j] = max(dp[j - 1] + a[j], get_max[j - 1] + a[j]);//我们可以把j看成是新的一段的起点!||第i个连在第j-1后面的段                //status[0][j-1]到status[i-1][j-1]的最大值,现在用get_max[j-1]进行表示。                get_max[j - 1] = Max;//枚举到j的最大值                Max = max(Max, dp[j]);            }        }        printf("%d\n", Max);    }    return 0;}