题目链接:https://vjudge.net/problem/POJ-2406
题目大意:
求一个字符串最多可以由多少个相同的子串组成。
知识点: KMP
解题思路:
利用 (KMP) 中 (next[]) 数组的性质:(next[j]) 表示字符串 (S[0, ... , j-1]) 的最长相同前后缀长度,也即 (S[j-t, j-t+1, ... , j-1]) 与 (S[next[j]-t, next[j]-t+1, ... , next[j]-1]) 相同,如图 (1) 所示。
当 (frac{j}{2} > next[j]) 时,很明显字符串没有循环节,(len mod (len - next[len]) eq 0),如图 (2) 的第 (1) 条线所示 ;
当 (frac{j}{2} le next[j]) 时,如果 (len mod (len - next[len]) = 0),那么图 2 中第三条线画圈的各段相同,而且整个字符串刚好有若干个如此的子段组成,因此答案即为 (frac{len}{len-next[len]}),其中,第二条线所示的 (len-next[len] = frac{len}{2}) 即为边界情况。
AC代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 7 using namespace std; 8 const int maxn=1e6+5; 9 10 char S[maxn]; 11 int len; 12 int Next[maxn]; 13 void GetNext() { 14 memset(Next, 0, sizeof(Next)); 15 int i = 0; 16 int j = -1; 17 Next[0] = -1; 18 19 while (i < len) { 20 if (j == -1 || S[i] == S[j]) { 21 i++, j++; 22 Next[i] = j; 23 } 24 else 25 j = Next[j]; 26 } 27 } 28 int main(){ 29 // freopen("in.txt","r",stdin); 30 while(scanf("%s",S)==1&&S[0]!='.'){ 31 len=strlen(S); 32 GetNext(); 33 if(len%(len-Next[len])==0) 34 printf("%d ",len/(len-Next[len])); 35 else 36 printf("1 "); 37 } 38 return 0; 39 }