Poj--2406(KMP,周期)
2014-12-12 23:55:35
思路:时隔半年,终于通过Matrix67的文章搞懂KMP了,orz。。。
这题加深了我对KMP本质的了解,题目让你求的是最长周期串的长度。
仔细考虑,我们发现get_P过程(就是另一种写法里的get_next),就是一种自我匹配找周期的过程!
【观察abcabcabc,P[9]=6,P[6]=3,P[3]=0,而且s[9]=s[6]=s[3],再者P[9]是从P[8]转移来的,换句话说是从P[6]转移过来的,P[6]=3说明包含s[6]在内的3个字符(s[3]->s[6])与头3个字符相等,而P[6]=6说明包含s[9]在内的6个字符(s[3]->s[9])与头6个字符相等。思考:P[6]说明abc这个周期重复2次,而P[9]说明abc这个周期重复了3次!
所以P可以理解为最大周期包含串长度(自己YY的玩意),abcabcabc的P[9]=6可以理解为前(9-6=3)个字符为周期,然后P[9]=6意思是以s[9]为终点的串包含了6个字符(也就是两个周期),我们命名这个串为周期包含串;再来个更普通的例子:abcabcab,P[8]=5,理解为前(8-5=3)个字符为周期,然后P[8]=5的意思是以s[8]为终点的周期包含串包含了5个字符,我们发现5个字符不是完整的两个周期,没错,差一个字符,回过去观察,的确差一个c才能形成两个周期。也就是说P[8]=5包含着以s[8]为终点的周期包含串正在形成第二个周期,但还没完成。
最后一个例子:abcbcabc,P[8]=3,理解为以s[8]为终点的周期包含串已经有了3个字符,但我们来看看周期是什么:8 - 3 = 5,也就是s[1]->s[5] : abcbc,显然P[8]还没包含一整个周期。以上解释纯属个人看完Matrix67文章后对本题的些许理解,望纠正与交流。】
1 /************************************************************************* 2 > File Name: 2406.cpp 3 > Author: Natureal 4 > Mail: 564374850@qq.com 5 > Created Time: Fri 12 Dec 2014 10:30:00 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 typedef unsigned long long ull; 26 const int INF = 1 << 30; 27 const int maxn = 1e6 + 10; 28 29 char s[maxn]; 30 int P[maxn]; 31 int len; 32 33 void Get_P(){ 34 P[1] = 0; 35 int j = 0; 36 for(int i = 2; i <= len; ++i){ 37 while(j > 0 && s[j + 1] != s[i]) j = P[j]; 38 if(s[j + 1] == s[i]) j++; 39 P[i] = j; 40 } 41 } 42 43 int main(){ 44 while(scanf("%s",s + 1) != EOF){ 45 if(s[1] == '.') 46 break; 47 len = strlen(s + 1); 48 Get_P(); 49 if(len % (len - P[len]) == 0) printf("%d\n",len / (len - P[len])); 50 else printf("1\n"); 51 } 52 return 0; 53 }
然后为了适应字符串index一般从0开始,写了一个从0开始的版本:
1 /************************************************************************* 2 > File Name: 2406.cpp 3 > Author: Natureal 4 > Mail: 564374850@qq.com 5 > Created Time: Fri 12 Dec 2014 10:30:00 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 typedef unsigned long long ull; 26 const int INF = 1 << 30; 27 const int maxn = 1e6 + 10; 28 29 char s[maxn]; 30 int P[maxn]; 31 int len; 32 33 void Get_P(){ 34 P[0] = -1; 35 int j = -1; 36 for(int i = 1; i < len; ++i){ 37 while(j >= 0 && s[j + 1] != s[i]) j = P[j]; 38 if(s[j + 1] == s[i]) j++; 39 P[i] = j; 40 } 41 } 42 43 int main(){ 44 while(scanf("%s",s) != EOF){ 45 if(s[0] == '.') 46 break; 47 len = strlen(s); 48 Get_P(); 49 if(len % (len - P[len - 1] - 1) == 0) printf("%d\n",len / (len - P[len - 1] - 1)); 50 else printf("1\n"); 51 } 52 return 0; 53 }