CodeChef 2017 March Challenge SCHEDULE - 烹饪计划

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

题目

大厨为接下来的 N 天定制了一个计划。在第 i 天,如果 Ai = 1,那么大厨会在那天工作;如果 Ai = 0,那么大厨就会休息。
大厨决定对这份计划做一些修改,最多修改 K 天的安排。大厨会选出最多 K 天,对于选出的每一天 i,如果 Ai = 1,则将其改成 0;否则将其改成 1。
修改之后应当保证,具有相同安排(即 Ai相等)的连续一段的日子天数最少。

题解

  1. 预处理出a[i]表示第i段连续相同的长度是多少。
  2. 二分答案lim,然后判断是否合法。
  3. 对于连续一段相同的,考虑不改变最左边和最右边的数,使当前段不会影响到相邻的段。那么我们每隔lim个数就改变一个数字,假如要改变最后一个数字,就变成改变倒数第二个数字以保证不改变最右边的数,这样一段需要改变的数字就是a[i]/(lim+1)判断一个总共改变数字的个数与k的关系即可。
  4. 但是当lim=1时不能保证不改变最左和最右的数,那么特判一下即可。
#include<bits/stdc++.h>
using namespace std;
char a[1000010];
int b[1000010],cnt,k,n;
bool check(int x)
{
    int s=0,i;
    for(i=1; i<=cnt; i++)
        s+=b[i]/(x+1);
    return s<=k;
}
int main()
{
    int t,i,l,r,ans,mid,x;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%s",&n,&k,a+1);
        cnt=1;
        b[1]=1;
        for(i=1; i<=n; i++)
        {
            if(a[i]==a[i-1]) b[cnt]++;
            else
            {
                cnt++;
                b[cnt]=1;
            }
        }
        x=0;
        for(i=1; i<=n; i++)
            if(a[i]-'0'==(i&1)) x++;
        if(x<=k||(n-x)<=k)
        {
            printf("1\n");
            continue;
        }
        l=2;
        r=n;
        ans=0;
        while(l<=r)
        {
            mid=(l+r)/2;
            if(check(mid)) r=mid-1,ans=mid;
            else l=mid+1;
        }
        printf("%d\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40032278/article/details/81532993