题目
大厨为接下来的 N 天定制了一个计划。在第 i 天,如果 Ai = 1,那么大厨会在那天工作;如果 Ai = 0,那么大厨就会休息。
大厨决定对这份计划做一些修改,最多修改 K 天的安排。大厨会选出最多 K 天,对于选出的每一天 i,如果 Ai = 1,则将其改成 0;否则将其改成 1。
修改之后应当保证,具有相同安排(即 Ai相等)的连续一段的日子天数最少。
题解
- 预处理出a[i]表示第i段连续相同的长度是多少。
- 二分答案lim,然后判断是否合法。
- 对于连续一段相同的,考虑不改变最左边和最右边的数,使当前段不会影响到相邻的段。那么我们每隔lim个数就改变一个数字,假如要改变最后一个数字,就变成改变倒数第二个数字以保证不改变最右边的数,这样一段需要改变的数字就是a[i]/(lim+1)判断一个总共改变数字的个数与k的关系即可。
- 但是当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;
}