kmp--nkoj2201周期

【KMP或后缀数组】周期

Description

对于字符串S(N个小写字母构成)的每个前缀,我们想知道该前缀是否会周期性的出现(就像循环节)。也就是对于每一个i(2 <= i <= N),我们想知道最大的一个k(k>1,如果存在)使得S的长度为i的前缀可以被写成Ak的形式,也就是连续k个字符串A。

Input

输入包含若干组测试数据,对于每组测试数据: 
第一行,一个整数N,表示字符串S (2 <= N <= 1 000 000) 的长度 
第二行,一个字符串S 
输入以单独一行,一个数字0作为结束

Output

对于每组测试数据: 
第一行,输出"Test case #"后面跟测试数据的编号 
接下来若干行,每行对应一个长度为i且满足k>1前缀,输出该前缀的长度和k的值,以空格作为间隔 
结果按前缀长度i升序排列。 
最后输出一个空行作为间隔。

Sample Input

3
aaa
12
aabaabaabaab
0

Sample Output

Test case #1
2 2
3 3

Test case #2
2 2
6 2
9 3
12 4

Hint

对于case1: 
长度为2的前缀"aa",可以写成a2,k的值为2 
长度为3的前缀"aaa",可以写成a3, k的值为3 

对于case2: 
长度为2的前缀"aa",可以写成a2,k的值为2 
长度为6的前缀"aabaab",可以写成(aab)2,k的值为2 
长度为9的前缀"aabaabaab",可以写成(aab)3,k的值为3 
长度为12的前缀"aabaabaab",可以写成(aab)4,k的值为4

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int fail[1000005];
char s[1000005];
int main(){
	std::ios_base::sync_with_stdio(false);
	int i,j,k,len,loop,cnt=0;
	while(scanf("%d",&len)&&len!=0){
		scanf("%s",s+1);
		cout<<"Test case #"<< ++cnt<<endl;
		memset(fail,0,sizeof(fail));
		j=0;
		for(i=2;i<=len;i++){
			while(j>0&&s[j+1]!=s[i])j=fail[j];
			if(s[j+1]==s[i])j++;
			fail[i]=j;
		}
		for(i=2;i<=len;i++){
			loop=i-fail[i];
		    if(i%loop==0&&i/loop>1)cout<<i<<" "<<i/loop<<endl;
		}
		cout<<endl;
	}
}


你可能感兴趣的:(kmp--nkoj2201周期)