uvalive3026 Period (KMP+结论)

题目链接: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 }
View Code

证明没有仔细说,不明白的欢迎留言讨论~

 

你可能感兴趣的:(live)