POJ2406 Power Strings

题目链接: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 \bmod (len - next[len]) \neq 0\),如图 \(2\) 的第 \(1\) 条线所示 ;

  当 \(\frac{j}{2} \le next[j]\) 时,如果 \(len \bmod (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\n",len/(len-Next[len]));
35         else
36             printf("1\n");
37     }
38     return 0;
39 }

 

posted @ 2017-11-12 14:27  Blogggggg  阅读(128)  评论(0编辑  收藏  举报