You are given an array a with n elements. Each element of a is either 0 or 1.
Let's denote the length of the longest subsegment of consecutive elements in a, consisting of only numbers one, as f(a). You can change no more than k zeroes to ones to maximize f(a).
Input
The first line contains two integers n and k (1 ≤ n ≤ 3·105, 0 ≤ k ≤ n) — the number of elements in a and the parameter k.
The second line contains n integers ai (0 ≤ ai ≤ 1) — the elements of a.
Output
On the first line print a non-negative integer z — the maximal value of f(a) after no more than k changes of zeroes to ones.
On the second line print n integers aj — the elements of the array a after the changes.
If there are multiple answers, you can print any one of them.
Examples
Input
7 1
1 0 0 1 1 0 1
Output
4
1 0 0 1 1 1 1
Input
10 2
1 0 0 1 0 1 0 1 0 1
Output
5
1 0 0 1 1 1 1 1 0 1
题意:
要求输入n和k,然后给出n个数的数列(皆为0或1),要求将n个数中最多修改k个数(0 ——>1),要求得到的修改之后的数列中有一个最多的连续的子序列全部由1组成。第一行输出这个子序列中的数字个数。第二行输出修改后的n个数。
方法一:(二分法)
这个题目可以用二分法过,nlogn。
外层循环就是固定子序列的左边界i,然后内层二分来找子序列右边界的。从第i个结点开始能得到的最大长度,它等于1的个数加上可以改变成1的0的个数。
方法二:(尺取法)
可以用尺取法来做,本来最先想到的是尺取法,但是做了之后有的地方超时,就以为是超时了,只能用二分,后来改了改,就ac了,尺取法也可以!
二分法代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int a[333333]; //存放n个数
int sum[333333]; //存放sum[1]到sum[i]之间一共有多少个1,
int main()
{
int n,k;
sum[0]=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
int num=0,rr,ll; //num存放全为1的子序列的长度,ll为子序列的左边界,rr为子序列的右边界
for(int i=1;i<=n;i++) //外层循环,固定左边界i
{
int l=i,r=n;
while(l<=r) //二分法不断地找符合的子序列的右边界
{
int mid=(l+r)/2;
if(mid-i+1<=k+sum[mid]-sum[i-1])
l=mid+1;
else
r=mid-1;
}
int ind=r;
if(ind-i+1>num) //更新最长子序列的长度
{
num=ind-i+1;
ll=i;
rr=ind;
}
}
printf("%d\n",num);
for(int i=ll;i<=rr;i++)a[i]=1;
for(int i=1;i<=n;i++)
{
if(i!=n)
printf("%d ",a[i]);
else
printf("%d",a[i]);
}
printf("\n");
return 0;
}
尺取法代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int main()
{
int n,k;
int a[333337];
while(scanf("%d%d",&n,&k)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
int l=0,r=0; //l存放子序列的左边界,r存放子序列的右边界
int maxn=0; //存放符合条件的子序列长度
int ll=1,num=0; //ll为尺子的左边界,num为左右边界之间的0的数量
for(int i=1;i<=n;i++) //i为不断向右移动的右边界
{
if(a[i]==0)
num++;
while(num>k) //如果左右边界之间0的数量大于k,左边界向右移动
{
if(a[ll]==0)num--;
ll++;
}
if((i-ll+1)>maxn)//更新符合条件的最长子序列的长度
{
maxn=i-ll+1;
r=i;
l=ll;
}
}
for(int i=l;i<=r;i++)
a[i]=1;
printf("%d\n",maxn);
for(int i=1;i<=n;i++)
{
if(i!=n)
printf("%d ",a[i]);
else
printf("%d",a[i]);
}
printf("\n");
}
return 0;
}