[Max Sum Plus Plus][HDU1024] DP
Description
HDU1024
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. _
Solution
在序列中找出m段连续字段使他们的和最大
dp[i][j]表示截至到第j个数字选i段子段的最大和
状态转移方程可以表示成\(dp[i][j] = max(dp[i][j-1], max\{dp[i-1][k]\})+s[j], i-1≤ k ≤ j-1\)
转移之后会把s[j]自动拼接到相应的状态之中,与之前的相连,或自己单独作为一段。
滚动数组优化掉i这一维,并用另一个数组记录max{dp[i-1][k]}
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int s[1000000 + 10];
int dp[1000000 + 10];
int last[1000000 + 10];
int main() {
//freopen("test.txt", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0);
int M, N;
while (cin >> M >> N) {
for (int i = 1; i <= N; i++) {
cin >> s[i];
}
int ans;
mem(dp,0);
mem(last,0);
for (int i = 1; i <= M; i++) {
ans = -INT_MAX;
for (int j = i; j <= N; j++) {
dp[j] = max(dp[j-1], last[j-1]) + s[j];
last[j-1] = ans;
ans = max(ans, dp[j]);
}
}
cout << ans << endl;
}
return 0;
}