A - Max Sum Plus Plus
Posted 佐鼬Jun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了A - Max Sum Plus Plus相关的知识,希望对你有一定的参考价值。
A - Max Sum Plus 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. _
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 3
2 6 -1 4 -2 3 -2 3
Sample Output
6
8
题意: 给n个数,选出m个子段(m个组),m个字段里的数必须是连续地,例如,
S
1
,
S
2
,
.
.
.
.
S
k
S1,S2,....Sk
S1,S2,....Sk,输出m个子段地最大和。
思路: 开个二维数组
f
[
i
]
[
j
]
f[i][j]
f[i][j]代表前
j
j
j个数分成
i
i
i组的最大和
此时要求
f
[
i
]
[
j
]
f[i][j]
f[i][j],就要对第j个数进行决策,是否分到第i个组里。
1.
1.
1.把第
j
j
j个数放进第i个组里,
f
[
i
]
[
j
]
=
f
[
i
]
[
j
−
1
]
+
a
[
j
]
f[i][j]=f[i][j-1]+a[j]
f[i][j]=f[i][j−1]+a[j]
2.
2.
2.不把第
j
j
j个数放进第
i
i
i个组里,而是自己开创一个新的组,也就是说前
k
k
k个数(0<k<j),成
i
−
1
i-1
i−1组,第
j
j
j个数自己开创一组,由于k有很多种情况,所以要取最大的情况,
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
−
1
]
[
k
]
)
+
a
[
j
]
)
f[i][j]=max(f[i-1][k] ) + a[j])
f[i][j]=max(f[i−1][k])+a[j])
综上所述, 动态转移方程
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
]
[
j
−
1
]
+
a
[
j
]
,
m
a
x
(
f
[
i
−
1
]
[
k
]
)
+
a
[
j
]
)
f[i][j]=max(f[i][j-1]+a[j],max(f[i-1][k] ) + a[j])
f[i][j]=max(f[i][j−1]+a[j],max(f[i−1][k])+a[j])
但是这个方程涉及三个参数,也就涉及三重循环,时间复杂度
O
O
O(n3
)
)
)
需要降维,把二维降低成一维,做等效变化。
把
f
[
i
]
[
j
]
f[i][j]
f[i][j]变成
f
[
j
]
f[j]
f[j],
f
[
i
]
[
j
−
1
]
f[i][j-1]
f[i][j−1]也是变成
f
[
j
−
1
]
f[j-1]
f[j−1],
m
a
x
(
f
[
i
−
1
]
[
k
]
)
max(f[i-1][k])
max(f[i−1][k])就需要新开一个数组
M
a
x
[
]
Max[]
Max[],来记录分成
i
−
1
i-1
i−1组前
k
k
k个数的最大值情况,
那么此时,方程就等效成了
f
[
j
]
=
m
a
x
(
f
[
j
−
1
]
+
a
[
j
]
,
M
a
x
[
j
−
1
]
+
a
[
j
]
)
f[j]=max(f[j-1]+a[j],Max[j-1]+a[j])
f[j]=max(f[j−1]+a[j],Max[j−1]+a[j])
此时时间复杂就降下来了,
O
(
n
m
)
O(nm)
O(nm)
注意: 这里说的前
i
−
1
i-1
i−1个数,不代表前
i
−
1
i-1
i−1个数全选,只是从
0
0
0到
i
−
1
i-1
i−1分成组后的最大值
int maxx;
for(int i=1;i<=m;i++) { //枚举分成几组
maxx=-inf;
for(int j=i;j<=n;j++) { ///前j个数分成i组,至少需要i个数
f[j]=max(f[j-1]+a[j],Max[j-1]+a[j]);
//Max[j-1]代表的是分成i-1个组,前面j-1数选择情况的最大值,a[j]单独一组组成i组
//f[j-1]代表j-1数分成i组的最大值,选上a[j]
Max[j-1]=maxx;
//因为maxx时j-1时,更新的,所以Max也要记录j-1时的
//因为Max时先调用再更新,所以Max[j-1]每次调用的时候
//都是调用的第i-1轮
maxx=max(maxx,f[j]);
//也是因为先吊用再更新,所以调用时的maxx其实上一次(j-1)的值
}
//每次循环完Max[]也就更新完了,方便下一轮(i+1轮)用
}
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
#define inf 0x3f3f3f3f
int a[N];
int f[N];
int Max[N];
int main() {
int m, n;
while (~scanf("%d%d", &m, &n)) {
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
memset(f, 0, sizeof(f));
memset(Max, 0, sizeof(Max));
int maxx;
for (int i = 1; i <= m; i++) {
maxx = -inf;
for (int j = i; j <= n; j++) {
f[j] = max(f[j - 1] + a[j], Max[j - 1] + a[j]);
Max[j - 1] = maxx;
maxx = max(maxx, f[j]);
}
}
cout<<maxx<<endl;
}
return 0;
}
To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激
以上是关于A - Max Sum Plus Plus的主要内容,如果未能解决你的问题,请参考以下文章
HDU 2746 ——Max Sum Plus Plus Plus
[2016-03-28][HDU][1024][Max Sum Plus Plus]
A - Max Sum Plus Plus (好题&&dp)