poj 2406 power strings
题意:给一个字符串,求长度最短的循环节。
题解:很经典的KMP的next数组的应用; 因为next数组代表模板串的最大公共前后缀,因此如果该字符串有循环节的话,那么从下标 next[len-1] 到 len-1 的这一段子串就代表了最短的循环节(不怎么明白的话可以求几个诸如abcabc、ababab 字符串的next数组出来研究下)。详见代码:
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <set> 7 #include <utility> 8 #include <vector> 9 #include <map> 10 #include <queue> 11 #include <stack> 12 const int inf=0x3f3f3f3f; 13 const double PI=acos(-1.0); 14 const double EPS=1e-8; 15 using namespace std; 16 typedef long long ll; 17 typedef pair<int,int> P; 18 19 char str[1000005]; 20 int next[1000005]; 21 void makeNext() 22 { 23 int q,k; 24 int m=strlen(str); 25 next[0]=0; 26 k=0; 27 for(q=1; q<m; q++) 28 { 29 while(k>0&&str[q]!=str[k]) k=next[k-1]; 30 if(str[k]==str[q]) k++; 31 next[q]=k; 32 } 33 //for(int i=0;i<=m;i++) printf("%d ",next[i]); 34 } 35 bool judge(int n) 36 { 37 int len=strlen(str); 38 if(len%n!=0) return false; 39 int cnt=len/n; 40 int t=0; 41 while(t<len) 42 { 43 for(int i=0,j=t;i<cnt;i++,j++) 44 if(str[i]!=str[j]) return false; 45 t+=cnt; 46 } 47 return true; 48 } 49 // 50 int main() 51 { 52 //freopen("test.txt","r",stdin); 53 while(scanf("%s",str)!=EOF) 54 { 55 int len=strlen(str); 56 if(len==1&&str[0]=='.') break; 57 makeNext(); 58 // 59 if((len-next[len-1])&&len%(len-next[len-1])==0) //len-next[len-1]得到一个循环节的长度 60 printf("%d\n",len/(len-next[len-1])); 61 else 62 printf("1\n"); 63 /* 64 65 一开始的蠢做法=_=... 66 int len=strlen(str); 67 len--; 68 int ans=1; 69 while(next[len]) ans++,len=next[len]-1;//得出有多少个循环节 70 if(judge(ans)) printf("%d\n",ans); //judge()判断长度为len/ans的循环节是否可行 71 else printf("1\n"); 72 */ 73 } 74 return 0; 75 }