【Codeforces Round #668 (Div. 2) C】Balanced Bitstring
题目链接
翻译
给你一个长度为 \(n\) 的字符串,让你判断这个字符串中是否每个长度为 \(k\) 的子串中 \(0\) 和 \(1\) 的个数都相同
这个字符串中只会包含 \(0\) 和 \(1\) 还有 ?
, 这里的 ?
是通配符。
题解
以 \(k=4\) 为例子, 假设 s[1..4]
是符合要求的, 那么我们紧接着看 s[2..5]
,不难发现。
s[2..5]
也满足要求的话,必然有 s[1]==s[5]
。因为, 整个字符串相当于少了一个 s[1]
然后多了一个 s[5]
。
所以有,对于任意的 \(i\) ∈ \([0..n-k]\) 有 s[i] = s[i+k]
。
那么我们只需要看 \(s[0..k-1]\) 这一段就好了,对于 \(i\) ∈ \([0..k-1]\),应该有 \(s[i]=s[i+k]=s[i+2*k]=...\)
那么对于 \(i,i+k,i+2*k...\) 这些字符要么全为 \(0\) (对于这样的 \(i\) 记录为 \(cnt0\) ) 要么全为 \(1\) (对于这样的 \(i\) 记录为 \(cnt1\)), 或者全是问号 (如果某个 \(i\) 里面有 \(0\) 又有 \(1\), 则直接无解)。
如果 \(cnt0\) 和 \(cnt1\) 的值都小于 \(k/2\),说明可以用全是问号的 \(i\) 进行补充使得 \(s[0..k-1]\) 这一段满足要求,即 \(0\) 和 \(1\) 的个数相同 (否则,无法凑够 \(0\) 和 \(1\) 一样,同样无解)。
只要第一段满足要求了,根据我们上面的 \(deduce\), 后面的所有长度为 \(k\) 的子串肯定也是满足要求的。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5;
int n, k, cnt[N + 10][2];
string s;
int main(){
#ifdef LOCAL_DEFINE
freopen("E://9.AlgorithmCompetition//Visitor.txt","r",stdin);
#endif
ios::sync_with_stdio(0),cin.tie(0);
int T;
cin >> T;
while (T--){
for (int i = 0;i < k; i++){
cnt[i][0] = cnt[i][1] = 0;
}
cin >> n >> k;
cin >> s;
for (int i = 0;i < n; i++){
if (s[i] == '0'){
cnt[i%k][0]++;
}else if (s[i] == '1'){
cnt[i%k][1]++;
}
}
bool ok = true;
int cnt0 = 0,cnt1 = 0;
for (int i = 0;i < k; i++){
if (cnt[i][0] > 0 && cnt[i][1] > 0){
ok = false;
break;
}else{
if (cnt[i][0] > 0){
cnt0++;
}else if (cnt[i][1] > 0){
cnt1++;
}
}
}
if (cnt0 > k/2 || cnt1 > k/2){
ok = false;
}
if (ok){
cout <<"YES"<< endl;
}else{
cout <<"NO"<<endl;
}
}
return 0;
}