*题解:P8945 Inferno
解析
记 \(b\) 为 \(a\) 的前缀和数组,\(c_i\) 表示 \(a[1,i]\) 中 \(0\) 的个数。考虑枚举区间右端点 \(r\),并寻找最优左端点 \(l\)。若 \(a[l,r]\) 中 \(0\) 的个数不超过 \(k\),即 \(c_r - c_{l - 1} \le k\),则填完 \(1\) 后该区间的和为 \(b_r - b_{l - 1} + c_r - c_{l - 1}\)。否则,区间和为 \(b_r - b_{l - 1} + k - (c_r - c_{l - 1} - k)\)。
对于前者,用单调队列维护满足条件的 \(l\) 中使得 \(-b_{l-1} - c_{l - 1}\) 最大的那个;对于后者,合法的 \(l\) 为一段前缀,统计 \(c_{l - 1} - b_{l - 1}\) 的最大值即可。
时间复杂度 \(O(n)\)。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 1e7 + 5,M = 60,K = 10000 + 5,mod = (int)1e9 + 7;
int a[N],b[N],c[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
// freopen("in.txt","r",stdin);
// freopen("out1.txt","w",stdout);
int n,k;
cin>>n>>k;
int j = 1,mx = -2e9;
deque<int> q;
int res = 0;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i] = b[i - 1] + a[i];
c[i] = c[i - 1] + (a[i] == 0);
while(j <= i && c[i] - c[j - 1] > k){
mx = max(mx,c[j - 1] - b[j - 1]);
j++;
}
while(!q.empty() && q.front() < j){
q.pop_front();
}
while(!q.empty() && - b[q.back() - 1] - c[q.back() - 1] < - b[i - 1] - c[i - 1]){
q.pop_back();
}
q.push_back(i);
int v1 = b[i] - c[i] + mx + 2 * k,v2 = b[i] + c[i] + (- b[q.front() - 1] - c[q.front() - 1]);
res = max({res,v1,v2});
}
cout<<res;
return 0;
}

浙公网安备 33010602011771号