ctq1999
2019-12-01 14:33:35
观察题目,发现不管怎么选,都只有两种情况:
1. ++++++---++++---
2. ++---+++++--++++
即要么是选两段的(对应
这样想就会把环拆成一条链
那么对于
f[i] = max(f[i - 1], 0) + a[i];
这样保证了扫描一遍后的
但并不是最优的那一段,因为在
所以再扫描一遍数组:
f[i] = max(f[i - 1], f[i]);
便得到了
因为是两段,所以设
res = max(res, f[i] + g[i + 1]);//注意因为不重叠,所以是g[i + 1]
这是第一种情况的做法
第二种求最优的三段的和,那么也就是总和减去不要的两段
那么把上面的
更简单的方法:把
若全是非正数,第二次跑会返回
若只有一个正数,第二次跑会把除它全不选,是错的,要特判
自己想想为什么,对以后的变形会有好处
#include <bits/stdc++.h>
#define MAXN 200010
using namespace std;
int n, ans, sum, positive_num;
int a[MAXN], f[MAXN], g[MAXN];
int ask() {
int res = -MAXN;
for (int i = 1; i <= n; i++) f[i] = max(f[i - 1], 0) + a[i];
for (int i = n; i >= 1; i--) g[i] = max(g[i + 1], 0) + a[i];
for (int i = 1; i <= n; i++) f[i] = max(f[i - 1], f[i]);
for (int i = n; i >= 1; i--) g[i] = max(g[i + 1], g[i]);
for (int i = 1; i < n; i++) res = max(res, f[i] + g[i + 1]);
return res;
}
int main() {
scanf("%d", &n);
memset(f, ~0x7f, sizeof(f));
memset(g, ~0x7f, sizeof(g));
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
sum += a[i];
if (a[i] > 0) positive_num++;
}
ans = ask();
if (positive_num == 1) {
cout << ans << endl;
return 0;
}
for (int i = 1; i <= n; i++) a[i] *= -1;
ans = max(ans, sum + ask() ? sum + ask() : -MAXN);
cout << ans << endl;
return 0;
}
日拱一卒,功不唐捐