1、
Max Sum Plus Plus
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. ^_^
InputEach 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.
OutputOutput 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
题目大意:给出n个数,求出m段不重复连续子串和的最大值。
(看完题目后并没有思路,于是查了博客=。=)
思路:
状态:dp[i][j]表示分成j块并以i为结尾的子段和最大值,mx[i][j]表示dp[0...i][0...j]的最大值。
划分策略:以a[i]单独为一组作为第j组,或a[i]作为前面组的一部分。
状态转移方程:如下。
1 //dp[i][j]意思为分成j块以a[i]结尾的和最大值,mx[i][j]存储着dp[j~i][j]中的最大值。 2 //划分策略为以a[i]单独为一组作为第j组,或a[i]作为前面组的一部分,所以状态转移方程为 3 //dp[i][j] = max(dp[i-1][j], mx[i-1][j-1]) + a[i] 4 //mx[i][j] = max(dp[i][j], mx[i-1][j]) 5 // for (int j=1;j<=m;j++) 6 // { 7 // for (int i=j;i<=n;i++) 8 // { 9 // if (i == j) dp[i][j] = dp[i-1][j-1] + a[i]; 10 // else dp[i][j] = max(dp[i-1][j] + a[i], mx[i-1][j-1] + a[i]); 11 // mx[i][j] = max(mx[i-1][j], dp[i][j]); 12 // } 13 // } 14 // for (int i=m;i<=n;i++) 15 // ans = max(ans, dp[i][m]);
空间压缩:但是题目范围不允许使用我们使用二维数组了,更何况两个,但是这里因为转移方程中调用的都是j-1或是i-1,所以我们可以压缩空间。dp[i] = max(dp[i-1], mx[i-1]) + a[i]中,i == j时,dp[i-1]存放的值为dp[i-1][j-1],mx[i-1]为mx[i-1][j-1];i != j时,dp[i-1]为dp[i-1][j], mx[i-1]为mx[i-1][j-1]。为了满足这个式子,dp数组只需照常填入即可,mx数组必须保证比dp数组慢一步,因为在填入dp[i]时必须保证mx[i-1]还未更新过,还没有从mx[i-1][j-1]变成mx[i-1][j]。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 const int M = 1e6+10; 6 int dp[M], mx[M]; 7 int a[M], n, m; 8 int main() 9 { 10 while (~scanf("%d%d", &m, &n)) 11 { 12 memset(dp, 0, sizeof(dp)); 13 memset(mx, 0, sizeof(mx)); 14 for (int i=1; i<=n; i++) 15 scanf("%d", &a[i]); 16 int q; 17 for (int j=1; j<=m; j++) 18 { 19 q = INT_MIN; 20 for (int i=j; i<=n; i++) 21 { 22 dp[i] = max(dp[i-1], mx[i-1]) + a[i]; 23 mx[i-1] = q; 24 q = max(q, dp[i]); 25 } 26 } 27 printf("%d\n", q); 28 } 29 }
总结:这个状态表示很巧妙。挺神奇的,这个状态是我以前没有写到过的。我目前对于dp的理解还很肤浅,解题思路都是从类似的题目偷过来的,而类似的题目最早是看答案的,意味着我不能独立思考dp问题,不过这一题让我对空间压缩有了一些自己的理解。继续努力吧,希望把这19题全部写完能对dp有自己的理解。
2、