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;
}
posted @ 2020-11-07 23:38  Tartarus_li  阅读(111)  评论(0编辑  收藏  举报