题目链接
翻译
给你一个长度为 (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;
}