思路一:
每次都向后改变m个,然后统计最长的连续的子串的长度。
注意要从当前位置p1开始,找到向后改变m+1个位置的p2,然后区间[p1+1,p2-1]内的是最长的连续的子串,
所以起始位置要从-1开始,结束位置为len。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5+10;
int s0[maxn],s1[maxn];
char ss[maxn];
int MIN(int x,int y){
return x<y?x:y;
}
int MAX(int x,int y){
return x>y?x:y;
}
int main(void)
{
int T,n,m,i,j;
scanf("%d",&T);
while(T--){
scanf("%d%d%s",&n,&m,ss);
int p1 = 0,p2 = 0;
s0[p1++] = -1;s1[p2++] = -1;
for(i=0;i<n;i++)
if(ss[i]=='0') s0[p1++] = i;
else s1[p2++] = i;
s0[p1] = n;s1[p2] = n;
int ans = 0;
for(i=0;i<p1;i++){
int k = MIN(p1,i+m+1);
ans = MAX(ans,(s0[k]-1)-(s0[i]+1)+1);
}
for(i=0;i<p2;i++){
int k = MIN(p2,i+m+1);
ans = MAX(ans,(s1[k]-1)-(s1[i]+1)+1);
}
printf("%d\n",ans);
}
return 0;
}
思路二:
二分求解,预处理求出0串,1串的前缀和,枚举每次要改变的元素个数,如果可以改变就得出结果。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5+10;
int p0[maxn],p1[maxn];
char ss[maxn];
bool pd(int x,int n,int m){
for(int i=0;i+x<=n;i++){
if(p0[i+x]-p0[i]+m>=x||p1[i+x]-p1[i]+m>=x) return true;
}
return false;
}
int main(void)
{
int T,n,m,i,j;
scanf("%d",&T);
while(T--){
scanf("%d%d%s",&n,&m,ss+1);
for(p0[0]=0,p1[0]=0,i=1;i<=n;i++)
if(ss[i]=='0') p0[i] = 1,p1[i] = 0;
else p1[i] = 1,p0[i] = 0;
for(i=1;i<=n;i++){
p0[i]+=p0[i-1];
p1[i]+=p1[i-1];
}
int l = 0,r = n;
while(l<=r){
int mid = (l+r)>>1;
if(pd(mid,n,m)) l = mid+1;
else r = mid-1;
}
printf("%d\n",r);
}
return 0;
}