题意:给定一个长为n(1<=n<=1e6)的数组,从其中找到不相交的m段,求能找出的m段中的数的和的最大值。
题解:状态转移方程,dp[i][j]表示第 i 个数被分在第 j 段的最优解。
- 因为没有给m,空间需要优化,优化成二维的。按照之前的思路直接将 j:=j&1 即可,这里,终于还是出问题了。
- 题解肯定是没错的,转化为一维的时候,一定要注意每个数的函数,而且dp[0][i],dp[1][i]因为不是数组中第一次赋值,需要特别注意。以下两行代码,坑我良多
既然是需要从dp[j-1...i-1][j-1]中更新,就一个也不能漏掉
限定只可能为前缀和
- 以上两点,认真思考倒也不难,可惜我就没有认真找过bug emm。太笃信之前的直接 j:=j&1
代码:
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
using namespace std;
const int N = 1e6 + 10;
const int INF = 2e9;
int n, m, a[N], sum[N];
int dp[N][2];
signed main() {
while (cin >> m >> n) {
memset(dp, 0, sizeof(dp));
int i, j;
for (i = 1; i <= n; i++) scanf("%d", &a[i]), sum[i] = sum[i - 1] + a[i];
/*
int mx = 0;
for (j = 1; j <= m; j++) {
mx = dp[j - 1][j - 1];
for (i = j; i <= n; i++) {
dp[i][j] = max(dp[i - 1][j] + a[i], mx + a[i]);
if (i == j) dp[i][j] = min(dp[i][j], sum[i]);
mx = max(mx, dp[i][j - 1]);
}
}
*/
//二维的话就是这样的,现在操作为一维:
int mx;
for (j = 1; j <= m; j++) {
mx = -INF;
//注意应该从j开始,如果i<j那是不可能构成j组的
mx = max(mx, dp[j - 1][!(j & 1)]);
for (i = j; i <= n; i++) {
dp[i][j & 1] = max(dp[i - 1][j & 1] + a[i], mx + a[i]);
if (i == j) dp[i][j & 1] = min(dp[i][j & 1], sum[i]);
mx = max(mx, dp[i][!(j & 1)]);
}
// cout << "j>>>" << j << endl;
// for (i = 0; i <= n; i++) cout << dp[i][j & 1] << " ";
// cout << endl;
}
int ans = -INF;
for (i = m; i <= n; i++) ans = max(ans, dp[i][m & 1]);
cout << ans << endl;
}
return 0;
}
/*
input:::
1 3 1 2 3
2 6 -1 4 -2 3 -2 3
output:::
6
8
*/