Hard Process
题目链接:
https://codeforces.com/contest/660/problem/C
Description
Input
Output
Sample Input
7 1
1 0 0 1 1 0 1
Sample Output
7 1
1 0 0 1 1 0 1
题意
给你一个长度为n的01串,最多可以把其中k个0变成1,问操作之后可以得到的最长的连续的1有多长。
题解:
首先考虑改变的k个0一定要是连续的,不然是没有意义的。
之后就可以采用尺取/二分的方法来解决这道题,这里讲一下二分的做法。
首先我们前缀和处理出到每个点为止0的个数。
之后枚举每一个作为连续的1的起点的情况。
如果到当前点为止0的个数为x,那么到第x+k个0这之间所有的0都可以变成1。
于是我们二分找到第一个0的个数大于等于x+k的位置,再加上当前点之前连续的1和这个位置之后连续的1的个数即可。按照这个方法枚举每一个位置作为更改0的起点的结果,取最大值即可。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define dbg(x) cout<<#x<<" = "<<x<<endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl
typedef long long ll;
const int maxn =3e5+10;
int a[maxn],pre[maxn];
int x[maxn],y[maxn];
int main()
{
//freopen(".in","r",stdin);
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) pre[i]=pre[i-1]+(a[i]==0);
for(int i=1;i<=n;i++)
{
if(a[i]==1) x[i]=x[i-1]+1;
else x[i]=0;
}
for(int i=n;i>=1;i--)
{
if(a[i]==1) y[i]=y[i+1]+1;
else y[i]=0;
}
int ans=-1,flag=-1;
for(int i=0;i<=n;i++)
{
int pos=lower_bound(pre+1,pre+1+n,pre[i]+k)-pre;
if(pos==n+1)
{
if(x[i]+n-i>ans) flag=i;
ans=max(ans,x[i]+n-i);
}
else if(pre[pos]==pre[i]+k)
{
if(x[i]+pos-i+y[pos+1]>ans) flag=i;
ans=max(ans,x[i]+pos-i+y[pos+1]);
}
}
if(flag==-1)
{
printf("0\n");
for(int i=1;i<=n;i++) printf("%d ",a[i]);
}
else
{
printf("%d\n",ans);
for(int i=1;i<=flag;i++) printf("%d ",a[i]);
for(int i=flag+1;i<=n;i++)
{
if(a[i]==1) printf("%d ",a[i]);
else
{
if(k>0)
{
k--;
printf("1 ");
}
else printf("0 ");
}
}
}
return 0;
}