Poj 1961 Period

题面

http://poj.org/problem?id=1961

题解

发现一个性质 一个循环的串 假设循环节长度为L 那么我们取其前size-L位,后size-L位,这两个串相同

相对应的,如果一个长度为size的串,我们取前k位,和后k位相同 那么size-k一定是这个串的循环节

所以我们只要对于每一位 找到前i位的子串的最长的前缀与对应长度的后缀相同的长度 那么i-length一定是答案

最长前缀=后缀 我们不难想到kmp的next数组

所以做一下kmp 求得next数组就做完了

复杂度$O(n)$

Code

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstdio>
 4 using namespace std;
 5 typedef long long ll;
 6 
 7 ll read(){
 8     ll x=0,f=1;char c=getchar();
 9     while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
10     while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
11     return x*f;
12 }
13 
14 int n;
15 char s[1000100];
16 int nxt[1000100];
17 
18 int main(){
19 #ifdef LZT
20     freopen("in","r",stdin);
21 #endif
22     int tc=0;
23     while(1){
24         n=read();
25         if(!n) break;
26         scanf("%s",&s);
27         nxt[0]=0,nxt[1]=0;
28         for(int i=1;i<n;i++){
29             int j=nxt[i];
30             while(j && s[i]!=s[j]) j=nxt[j];
31             nxt[i+1]=(s[i]==s[j])?j+1:0;
32         }
33         printf("Test case #%d
",++tc);
34         for(int i=1;i<=n;i++){
35             if(i%(i-nxt[i])==0 && nxt[i]){
36                 printf("%d %d
",i,i/(i-nxt[i]));
37             }
38         }
39         puts("");
40     }
41     return 0;
42 }

Review

动机?

kmp的一个功能就是处理循环串

这算是个模板题?

原文地址:https://www.cnblogs.com/wawawa8/p/9403392.html