题意:给出一个字符串s(len<=5e5),求他的所有的循环节长度(循环节匹配到最后一节原串长度不足也符合题意),有多组测试。字符串总长度不超过5e5
题解:正解是FFT,但是弱弱我看了一整天刚刚看得懂理论,代码还没看得懂呢。只好暴力过了这个题。
类似于素数筛的方法。假设找到了一个length是循环节,那么显然length的倍数也是循环节。完全类似于素数筛。
注意:既然都暴力了,那么像memset这种操作就不要memset(can,false,.sizeof(can))这种暴力的操作了,清空需要的部分就可以了。否则自找TLE。
Code:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 500005
map<int,int> mp;
char s [MAXN];
int n,k;
bool can [MAXN];
bool check(int length){
for (int i = 1;i<=length;i++){
char who = s[i];
int now = i+length;
while (now<=n){
if (who!='?'&&s[now]!='?'&&who!=s[now])return false;
if (s[now]!='?') who = s[now];
now+=length;
}
}
return true;
}
int main(){
scanf("%d",&k);
while (k--){
scanf("%d%s",&n,s+1);
int sum = 0;
memset (can,false,sizeof(bool)*(n+2));
mp.clear();
for(int i = 1; i <=n; ++ i) mp[s[i]] = 1;
if(mp['V'] + mp['K'] <= 1){
printf("%d\n", n);
for(int i = 1; i <= n; ++ i) printf("%d%c", i, i == n ? '\n' : ' ');
continue;
}
for (int i=2;i<=n;i++){
if (can[i]){
continue;
}else if (check(i)){
for (int j=i;j<=n;j+=i){
can[j]=true;
}
}
}
for (int i=2;i<=n;i++){
sum+=can[i];
}
printf("%d\n",sum);
for (int i=1;i<=n;i++){
if (can[i]){
printf("%d ",i);
}
}
printf("\n");
}
return 0;
}