萌新求助,赛时 20pts。
做法是在枚举左端点后,先考虑答案段选不满 k 个 1 的情况,用单调队列维护 sumi+havi;再考虑选满 k 个 1 之后和最大的一个前缀 。其中 sumi 表示原数组的前缀和, havi 表示 [1,i] 中总共出现了几个 0 。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e7 + 10;
int n, k, l, r, ans, tot;
int q1[N], q2[N];
int a[N], maxn[N], sum[N], is[N], hav[N];
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> k;
l = 1, memset(maxn, -0x3f, sizeof(maxn));
for(int i = 1; i <= n; i++)
cin >> a[i];
for(int i = 1; i <= n; i++) {
sum[i] = sum[i - 1] + a[i], is[i] = is[i - 1] + (a[i] == 1 ? 1 : -1);
if(!a[i])
maxn[++tot] = sum[i];
maxn[tot] = max(maxn[tot], sum[i]), hav[i] = tot;
}
for(int i = n; i >= 1; i--) {
while(l <= r && q1[l] > hav[i] + k - (a[i] == 0))
l++;
//cout << l << " " << r << " " << q2[l] << " " << hav[i] << " " << sum[i - 1] << " " << a[i] << endl;
if(l <= r)
ans = max(ans, q2[l] - hav[i] + (a[i] == 0) - sum[i - 1]);
if(a[i])
continue;
while(l <= r && maxn[hav[i] + hav[i]] > q2[r])
r--;
q1[++r] = hav[i], q2[r] = maxn[hav[i]] + hav[i];
}
//cout << ans << endl;
l = -2147483647, r = 0;
for(int i = n; i >= 1; i--) {
if(is[i] > l)
l = is[i], r = i;
// cout << l << " " << r << " " << l - is[i - 1] + 2 * max(hav[r] - hav[i], k) << endl;
ans = max(ans, l - is[i - 1] + 2 * min(hav[r] - hav[i] + (a[i] == 0), k));
}
cout << ans;
return 0;
}