pku 1961 http://poj.org/problem?id=1961
题意:
给定一个长度为n的字符串,求他的前缀且前缀满足本身为周期字符串。例:aabaabaab 长度为9 周期为3
思路:
kmp几乎忘干净了,开始学的时候也没有真正的理解,今天看了好长时间的getnext函数;我们在对字符串本身处理得到next函数时,
next[i]记录的就是s[1,next[i]] 与s[i - next[i] + 1,i]相同时的值,这里next[i]也表示了相同区间的长度,我们的坐标从0开始则只要(i + 1)%(i - next[i]) == 0就能满足该字符串前缀是周期字符串,i+1表示的是当前枚举到的字符串的长度,(i - next[i])表示的就是一个周期的字符长度了。
#include <cstdio> #include <iostream> #include <cstring> #define maxn 1000004 using namespace std; int next[maxn]; void GetNext(char *s) { int len = strlen(s); int i,j; i = 0; j = -1; next[0] = -1; for (i = 1; i < len; ++i) { while (j > -1 && s[j + 1] != s[i]) j = next[j]; if (s[j + 1] == s[i]) ++j; next[i] = j; } } int main() { int n,i; char s1[maxn]; int cas = 1; while (~scanf("%d",&n)) { if (!n) break; printf("Test case #%d\n",cas++); scanf("%s",s1); GetNext(s1); for (i = 0; i < n; ++i) { int d = (i + 1)%(i - next[i]); if (d == 0 && next[i] != -1) { printf("%d %d\n",i + 1,(i + 1)/(i - next[i])); } } printf("\n"); } return 0; }
pku 2406 http://poj.org/problem?id=2406
同上:类似的题目:
#include <cstdio> #include <iostream> #include <cstring> #define maxn 1000004 using namespace std; int next[maxn]; void GetNext(char *s,int len) { int i = 0,j = -1; next[0] = -1; for (i = 1; i < len; ++i) { while (j > -1 && s[j + 1] != s[i]) j = next[j]; if (s[j + 1] == s[i]) ++j; next[i] = j; } } int main() { char s[maxn]; int i; while (gets(s)) { if (s[0] == '.') break; int len = strlen(s); if (len == 0) { puts("0"); continue; } GetNext(s,len); if (len%(len - 1 - next[len - 1]) == 0) printf("%d\n",len/(len - 1 - next[len - 1])); else printf("1\n"); } }
pku 3461 Oulipo http://poj.org/problem?id=3461
提议:
给你两个字符串,w,t查看字符串w在t中出现的次数;
思路:
kmp模式匹配,关键是到那个查找到其为子串时继续查找。
#include <cstdio> #include <iostream> #include <cstring> #define maxn 1000004 using namespace std; int next[maxn]; char W[maxn],T[maxn]; void GetNext(char *s) { int i = 0,j = -1; int len = strlen(s); next[0] = -1; for (i = 1; i < len; ++i) { while (j > -1 && s[j + 1] != s[i]) j = next[j]; if (s[j + 1] == s[i]) ++j; next[i] = j; } } void kmp(char *s1,char *s2)//s1副串 s2主串 { int len1 = strlen(s1); int len2 = strlen(s2); int i,j = -1; int ans = 0; for (i = 0; i < len2; ++i) { while (j > -1 && s1[j + 1] != s2[i]) j = next[j]; if (s1[j + 1] == s2[i]) ++j; if (j == len1 - 1)//找到子串,后继续查找 { ans++; j = next[j]; } } printf("%d\n",ans); } int main() { int n; while (~scanf("%d",&n)) { scanf("%s%s",W,T); GetNext(W); kmp(W,T); } return 0; }