AcWing 141 周期 (KMP)
题目链接:https://www.acwing.com/problem/content/description/143/
引理:\(S[1~i]\) 具有长度为 \(len < i\) 的循环元的充要条件是 \(len\) 能整除 \(i\), 并且
\(S[len+1~i] = S[1~i-len]\)
还有个小性质:一个字符串的任意循环元的长度必然是最小循环元长度的倍数
证明:
如果存在循环元长度不是最小循环元长度的倍数,则肯定存在长度为较长循环元长度模最小循环元长度的循环元,
此循环元比最小循环元小,矛盾
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 1000010;
int n;
int nxt[maxn];
char s[maxn];
ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
int main(){
int Case = 0;
while(n = read()){
if(!n) break;
scanf("%s",s + 1);
printf("Test case #%d\n",++Case);
nxt[1] = 0;
for(int i=2, j=0;i<=n;++i){
while(j && s[i] != s[j+1]) j = nxt[j];
if(s[i] == s[j+1]) ++j;
nxt[i] = j;
}
for(int i=2;i<=n;++i){
int j = nxt[i];
if((i % (i - nxt[i])) == 0 && nxt[i] != 0) printf("%d %d\n",i, i / (i - j));
}
printf("\n");
}
return 0;
}