[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;
}

posted @ 2020-03-30 17:57  EZ4ZZW  阅读(149)  评论(0编辑  收藏  举报