翻译
思路
由于每次操作区间长度是定值,所以我们可以说,如果最前面的数已经是1了,那它再也不会被进入操作。因为如果把它变回0,那想再变成1只能以它为起点再操作一次,前后两次操作抵消。
所以思路很简单,直接 O ( n ) O(n) O(n)倒序遍历 k k k, O ( n ) O(n) O(n)判断是否能行,而判断只需从左往右扫一遍,遇到 0 0 0则操作一次,否则直接过,用队列维护当前点处被几个区间覆盖即可。
代码
#include<bits/stdc++.h>
#define N 5003
using namespace std;
int t, ans, n, a[N];
queue<int> q; // 存起点下标
bool check(int k) {
while(!q.empty()) q.pop();
int cnt = 0;
for(int i=1;i<=n+1;i++) { // 遍历到n+1是为了处理剩余区间,方便判断
while(!q.empty() && i-q.front()+1 > k) {
q.pop();
cnt--;
}
if(i == n+1) continue;
if(a[i] + cnt & 1) { // 当前是1
continue;
} else { // 当前是0
cnt ++;
q.push(i);
}
}
// 如果合法,那使用的区间起点不应该在最后k-1个位置,也就是说遍历完后队列应该为空
return q.empty();
}
int main() {
cin>>t;
while(t--) {
cin>>n;
string s; cin>>s;
for(int i=0;i<s.length();i++) a[i+1] = s[i] - '0';
for(int k=n;k>=1;k--) {
if(check(k)) {
ans = k;
break;
}
}
cout<<ans<<endl;
}
return 0;
}