杭电1024Max Sum Plus Plus
地址:http://acm.hdu.edu.cn/showproblem.php?pid=1024
题目:
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. ^_^
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.
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.一开始,题目都没看懂,(os:题目讲的什么鬼,英语差就是心酸= =)
后来看懂了题目意思后也没做出来,没想到那种dp方法,好心累,估计是dp题做得少的原因吧。。
之后看了看了几个人的博客,才会的,原地址http://blog.csdn.net/lishuhuakai/article/details/8067474
还有一个的忘了。。。
先讲下题目意思吧:先讲下连续最大子段和,就是给你n个数,a[1]....1[n],求a[i]+.a[i+1]...+a[j]的最大值。
此时状态转移方程:dp[i]=a[i]+(dp[i-1]>0?dp[i-1]:0)(dp【i】代表选了a【i】时的最大子段和)
呃,不知道怎么表达了,上图吧:
dp[i]\a[i] | 2 | -1 | 3 | -8 | 9 |
1 | 2 | ||||
2 | 1 | ||||
3 | 4 | ||||
4 | -4 | ||||
5 | 9 |
对于连续最大和,只需要扫描一遍数组就好了
1024题呢,就是把n个数分成x(x∈[m,n])段后,求这其中m个的子段和(不相交)的最大值;
由连续最大子段和的解法可以推广到求m个最大字段和,
dp[i][j] = max(dp[i][j-1],max(dp[i-1][k]))+a[j];(i-1<=k<=j-1)
其中dp【i】【j】时,前j个元素中取i个子段的最大和(一定取了a【j】)
所以由dp[i][j-1]到dp[i][j] 时,有两种取法:
1:a[j]和前一个以a[j-1]的子段合并
2:独立成一个子段;
以题目的第二组数据为例:
dp i\j) | -1 | 4 | -2 | 3 | -2 | 3 |
1 | -1 | 4 | 2 | 5 | 3 | 6 |
2 | \ | 3 | 2 | 7 | 5 | 8 |
3 | \ | \ | 1 | 6 | 5 | 10 |
4 | \ | \ | \ | 4 | 4 | 9 |
5 | \ | \ | \ | \ | 2 | 7 |
maxtemp | \ | \ | \ | \ | \ | \ |
1 | -1 | 4 | 4 | 5 | 5 | \ |
2 | \ | 3 | 3 | 7 | 7 | \ |
3 | \ | \ | 1 | 6 | 6 | \ |
4 | \ | \ | \ | 4 | 9 | \ |
5 | \ | \ | \ | \ | 2 | \ |
\ | \ | \ | \ | \ |
没写的代表不用算。。。
这样dp方程就有了,不过因为题目所给的数据较大,1 ≤ n ≤ 1,000,000,
空间复杂度:m*n,很容易就超了
时间复杂度:n^3,也是会超的
所以继续优化,容易看出,每次使用dp方程时,其实只涉及到两个数组dp[i][k]和dp[i-1][k],所以可以化简为两个数组dp1[i],dp2[i]储存。
这样空间复杂度就降低到m了
然而时间复杂度没变,继续优化,我们可以用另一个数组maxtemp[i]来储存max(dp[i-1][k])(i-1<=k<=j-1),
所以dp方程变为:
dp[i][j] = max(dp[i][j-1],maxtemp[i-1])+a[j];
这样时间复杂度就变成n^2了,可以接受了。
其实,空间还可以优化,用一个dp数组就可以了,因为dp[i]从左向右递推时,只和dp[i-1],maxtemp[i-1]有关,
所以可以删去dp2[i].
上代码:
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cmath> 5 #include <cstring> 6 #include <queue> 7 #include <stack> 8 #include <map> 9 #include <vector> 10 11 #define N 1000010 12 #define PI acos((double)-1) 13 #define E exp(double(1)) 14 using namespace std; 15 int dp1[N]; 16 int maxtemp[N]; 17 int a[N]; 18 19 int main(void) 20 { 21 int n, m, max1; 22 while (scanf("%d%d", &m, &n) == 2) 23 { 24 for (int i = 1; i <= n; i++) 25 scanf("%d", &a[i]); 26 dp1[1] = maxtemp[1] = max1 = a[1]; 27 for (int i = 2; i <= n; i++) 28 { 29 if (max1 >= 0) 30 { 31 dp1[i] = a[i] + max1; 32 max1 += a[i]; 33 } 34 else 35 { 36 dp1[i] = a[i]; 37 max1 = a[i]; 38 } 39 } 40 for (int i = 2; i <= m; i++) 41 { 42 maxtemp[i-1] = dp1[i-1]; 43 for (int j = i ; j < n; j++) 44 { 45 if (maxtemp[j - 1]<dp1[j]) 46 { 47 maxtemp[j] = dp1[j]; 48 } 49 else 50 maxtemp[j] = maxtemp[j - 1]; 51 } 52 for (int j = i; j <= n; j++) 53 { 54 if (i == j) 55 dp1[j] = maxtemp[j - 1] + a[j]; 56 else 57 dp1[j] = max(dp1[j - 1], maxtemp[j - 1]) + a[j]; 58 } 59 } 60 max1 = dp1[m]; 61 for (int i = m; i <= n; i++) 62 if (max1<dp1[i]) 63 max1 = dp1[i]; 64 cout << max1 << endl; 65 66 } 67 return 0; 68 }
作者:weeping
出处:www.cnblogs.com/weeping/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。