Codeforces 660C Hard Process【二分】经典题!好题!

C. Hard Process
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given an array a with n elements. Each element of a is either0 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 thank zeroes to ones to maximize f(a).

Input

The first line contains two integers n andk (1 ≤ n ≤ 3·105, 0 ≤ k ≤ n) — the number of elements ina and the parameter k.

The second line contains n integers ai (0 ≤ ai ≤ 1) — the elements ofa.

Output

On the first line print a non-negative integer z — the maximal value off(a) after no more than k changes of zeroes to ones.

On the second line print n integers aj — the elements of the arraya 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个数,元素只有两种,要么是1,要么是0,我们最多可以让K个0变成1,让我们找连续最长子序列(元素只有1)的长度。


思路:


我们O(n)枚举这段连续最长子序列的起点,然后枚举终点。

显然直接枚举终点需要O(N^2)的总时间复杂度,是不可行的,那么考虑其特性:枚举出来的终点越远,其0的个数就越可能多,那么形成可行序列的概率就越小。

那么显然其具有一个单调性。

接下来考虑二分终点,那么目标时间复杂度O(NLogN);

那么接下来我们只要维护一个区间前缀和即可,设定为pre【i】,表示区间【1,i】中有多少个0.

那么对于我们枚举出来的起点和终点,如果其中包含0的个数小于等于K个,那么此区间就有可能是解区间,维护最大那个即可。


Ac代码:

#include<stdio.h>
#include<string.h>
using namespace std;
int a[1000060];
int pre[1000060];
int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        memset(pre,0,sizeof(pre));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            pre[i]=pre[i-1];
            if(a[i]==0)pre[i]++;
        }
        int s=-1;
        int e=-1;
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            int l=i;
            int r=n;
            while(r-l>=0)
            {
                int mid=(l+r)/2;
                if(pre[mid]-pre[i-1]<=k)
                {
                    if(ans<mid-i+1)
                    {
                        ans=mid-i+1;
                        s=i;e=mid;
                    }
                    l=mid+1;
                }
                else r=mid-1;
            }
        }
        printf("%d\n",ans);
        for(int i=1;i<=n;i++)
        {
            if(i>=s&&i<=e)
            {
                printf("1 ");
            }
            else printf("%d ",a[i]);
        }
        printf("\n");
    }
}






  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值