题目链接:http://vjudge.net/problem/viewProblem.action?id=29342
题目大意:给定字符串,找到每个前缀的最大循环节的个数。
首先当然是kmp预处理,接下来的问题是 怎么找循环节?
用反证法可以证明,如果f[i]~i之间的字符串能构成循环节,则该字符串就是i前缀对应的循环节,否则循环节不存在。
对每个前缀找到尾指针对应的失陪位置后,不需要按失陪指针继续往前寻找了(否则超时)。
只用判断上个位置到尾部的字符串是否是循环节(长度是否有整除关系),即知循环节个数。
代码奉上:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <stdlib.h> 4 #include <cstring> 5 6 int f[1000010]; 7 char p[1000010]; 8 void deal(int l){ 9 f[0]=-1; 10 int i=0,k=-1; 11 while(i<l){ 12 if(k==-1 || p[k]==p[i])f[++i]=++k; 13 else k=f[k]; 14 } 15 //for(i=0;i<l;i++)printf("%d: %d\n",i,f[i]); 16 } 17 int main(){ 18 int n,cs=1; 19 while(scanf("%d",&n) && n){ 20 scanf("%s",p); 21 deal(n); 22 printf("Test case #%d\n",cs++); 23 int i,k; 24 for(i=1;i<=n;i++){ 25 if(f[i]==0 || i%(i-f[i]))continue; 26 k=i/(i-f[i]); 27 if(k>1)printf("%d %d\n",i,k); 28 } 29 printf("\n"); 30 31 } 32 return 0; 33 }
证明没有仔细说,不明白的欢迎留言讨论~