HDOJ102-Ma-Su-Plu-Plus
题目描述
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. ^_^
输入
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 the maximal summation described above in one line.
输入示例
1 3 1 2 3
2 6 -1 4 -2 3 -2 3
输出示例
6
8
Hint
Huge input, scanf and dynamic programming is recommended.
题目大意:
给定n个数,让其划分为k个不重叠的区间(不要求连续),求其中的最大值。
思路:
因为给定一个区间,它的最大值是确定的,所以具有无后效性,所以我们考虑使用dp来解此题。
我们首先定义状态表示,很自然的想到:
1 | dp[i][j] = dp[i][j] 表示将前i个数字分成j段的最大子段和。 |
接下来考虑状态转移方程:
我们将状态转移分为:
- 与前面划分的区间不合并,即自成一组。
- 与前面划分的区间合并为一组。
第二种转移方程比较好考虑:
1 | dp[i][j] = dp[i-1][j] + v[i]; |
自成一组需要找上一组从哪里转移。由于不需要保证连续性,所以就需要从第一段一直到j-1段都要考虑到。
1 | dp[i][j] = max{dp[k][j-1](1 <= k < i)} |
由于只有k个长度的字符才能分成k段。所以这里取值范围应该改为:
1 | dp[i][j] = max{dp[k][j-1](j-1 <= k < i)} + v[i] |
综合一下就是:
1 | dp[i][j] =max( dp[i-1][j], max{dp[k][j-1](j-1 <= k < i)} ) + v[i] |
分析工作准备完毕,我们准备写代码时发现,这个数组范围比较大,会O(n2)的算法会超时,所以要优化。
第二种转移方程没什么好优化的,我们转移到第一种上,它在转移上依赖了他之上的好多行的数组,列却只依赖一列。这里想象为二维数组,我们把行,列的含义互换,想象这个二维数组逆时针旋转了90度。
就得到了如下的转移方程:
1 | dp[i][j] = dp[i][j] 表示将前j个数字分成i段的最大子段和。 |
1 | dp[i][j] =max( dp[i][j-1], max{dp[i-1][k](i-1 <= k < j)} ) + v[j] |
我们可以将 max{dp[i-1]k} 这个O(n)的时间,在上一层的d[i-1][j]计算结果时用一个变量来记录,使其优化为O(1)。
具体编程还是有些难度,需要好好思考。
1 | /* |