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
*/
标签:Process,复杂度,Hard,个数,mid,len,int,check
From: https://www.cnblogs.com/lghjl/p/18442334