*题解: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;
}

posted @ 2026-08-29 15:56  yutar  阅读(2)  评论(0)    收藏  举报