Hard Process

Hard Process(题面)
大意:给定一个长度为\(n(0<=n<=10^5)\)的序列,序列中只包含0或1,现有k次机会可以将0改为1,问,k次机会前最长连续1序列的长度并且输出这个序列(只需一个)。
解法:二分答案+前缀和

证二分答案的单调性:

先解释check函数:现有一个需要查询的长度len,从1开始直到n,遍历每一个长度为len的0的个数,如果个数小于等于k的话,那么这个长度就是可以满足的。
我们会发现,长度越长,包含0的个数理论上会更长,需要的次数理论上也就更多,所以就满足二分的单调性。

前缀和的作用:

check函数中需要遍历每一个长度为len的0的个数,复杂度就为\(O(n^2)\),显然是不能接受的。那么我们可以预处理出来从1到i所有0的个数,那么我们想要求出$l-r$0的个数,只需要用\(1-l\) 0的个数- \(1-(r-1)\) 0的个数即可求出。复杂度就会变成\(O(n)\)

复杂度:

二分的复杂度是\(O(log\) \(n)\),check函数的复杂度为\(O(n)\),总复杂度就是\(O(n log\) \(n)\)
code:

#include <iostream>
using namespace std;

int n, k, ans, z, y;
int a[300001], b[300001];

bool check(int len, int& z, int& y) {
	for(int i = 1 ; i + len - 1 <= n ; i ++) {
		int need = a[i + len - 1] - a[i - 1];
		if(need <= k) {
			z = i, y = i + len - 1;
			return true;
		}
	}
	return  false;
}

int main() {
	
	cin >> n >> k;
	for(int i = 1 ; i <= n ; i ++) {
		cin >> a[i];
		b[i] = a[i];
		a[i] = a[i - 1] + !(a[i]);
	} 
	int l = 0, r = 99999999;
	while(l < r) {
		int mid = (l + r + 1) / 2;
		int x = 0, c = 0;
		if(check(mid, x, c)) {
			ans = mid;
			z = x, y = c;
			l = mid;
		}else r = mid - 1;
	}
	cout << ans << '\n';
	for(int i = 1 ; i <= n ; i ++) {
		if(i == z) {
			for(int j = z ; j <= y ; j ++) {
				cout << 1 << ' '; 
			}
			i = y;
		}
		else cout << b[i] << ' ';
	}
}
/*
10 2
1 0 1 0 1 0 1 0 0 1
*/
posted @ 2024-09-30 18:56  lghjl  阅读(22)  评论(0)    收藏  举报