1. 程式人生 > >poj1961 Period kmp解決找字符串的最小循環節

poj1961 Period kmp解決找字符串的最小循環節

ext mes com tex 最大的 std str 開始 space

/**
題目:poj1961 Period
鏈接:http://poj.org/problem?id=1961
題意:求從1到i這個前綴(2<=i<=N) ,如果有循環節(不能自身單獨一個),輸出前綴字符串長度以及最大的循環周期;
思路:
參考自:http://www.cnblogs.com/chenxiwenruo/p/3546457.html
定理:假設S的長度為len,則S存在最小循環節,循環節的長度L為len-next[len],子串為S[0…len-next[len]-1]。

(1)如果len%(len - next[len])==0,則表明字符串S可以完全由循環節循環組成,循環周期T=len/L。(這裏的len就是從0開始的len位置,kmp也計算了next[len]。)

(2)如果不能,說明還需要再添加幾個字母才能補全。需要補的個數是循環個數L-len%L=L-(len-L)%L=L-next[len]%L,L=len-next[len]。

----------------------------
*/ #include <cstdio> #include <cstring> #include <algorithm> #include <set> #include <queue> #include <iostream> #include <vector> using namespace std; #define ms(x,y) memset(x,y,sizeof x) const int N = 1e6 + 10; const int inf = 0x3f3f3f3f; char s[N]; int f[N];
void getFail(char* P,int* f) { int m = strlen(P+1); f[1] = f[2] = 1; for(int i = 2; i <= m; i++){ int j = f[i]; while(j!=1&&P[i]!=P[j]) j = f[j]; f[i+1] = (P[i]==P[j])?j+1:1; } } int main() { int n; int cas = 1; while(scanf("%d",&n)==1
&&n) { scanf("%s",s+1); getFail(s,f); printf("Test case #%d\n",cas++); for(int i = 3; i <= n+1; i++){ if((i-1-(f[i]-1))==i-1) continue;//不能以自身為一個循環節。即循環周期至少為2. if((i-1)%(i-1-(f[i]-1))==0){ printf("%d %d\n",i-1,(i-1)/(i-1-(f[i]-1))); } } puts(""); } return 0; }

poj1961 Period kmp解決找字符串的最小循環節