Hard Process CodeForces - 660C ( 二分法 或 尺取法 )

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SEVENY_/article/details/83112597

 Hard Process

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;
}

猜你喜欢

转载自blog.csdn.net/SEVENY_/article/details/83112597