本题需要 求字符串的最小循环节,有两种方法:
哈希
根据哈希的性质,如果最小循环节的长度为 ,那么每 长度的字符串的哈希值是相等的,那么我们只需预处理前 长度的哈希值以及 进制的 次方,然后根据哈希的如下性质便可以平均 的复杂度计算出最小循环节:
时间复杂度
char s[maxn];
ull base=131;
ull hashe[maxn],bn[maxn];
void init(){
int n=strlen(s+1);
hashe[0]=0,bn[0]=1;
for(int i=1;i<=n;i++)
hashe[i]=hashe[i-1]*base+(ull)s[i];
for(int i=1;i<maxn;i++)
bn[i]=bn[i-1]*base;
}
bool check(int x,int n){
ull pre=hashe[x];
for(int i=2*x;i<=n;i+=x){
ull cur=hashe[i]-hashe[i-x]*bn[x];
if(cur!=pre) return 0;
}
return 1;
}
void solve(){
int n=strlen(s+1);
for(int i=1;i<=n;i++){
if(n%i==0 && check(i,n)){
printf("%d\n",n/i);
break;
}
}
}
KMP的next数组
实际上next数组解决的最大前缀后缀匹配长度,如果一个串是循环字符串,那么一定有 ,例如:
int Next[maxn];
void initNext(char *p){
int len=strlen(p);
int k=-1,j=0;
Next[0]=-1;
while(j<len){
if(k==-1 || p[j]==p[k]){
Next[++j]=++k;
}else k=Next[k];
}
}
int solve(char *s){
initNext(s);
int n=strlen(s);
if(n%(n-Next[n])==0) return n/(n-Next[n]);
return 1;
}