kmp入门小结
void get_next(char *s) { int len = strlen(s); int j = 0; int k = -1; while (j < len){ if (k == -1 || s[j] == s[k]){ j++; k++; next[j] = k; } else k = next[k]; } }
设t = next[i]; next[i] 表示的是 i之前最大的t满足 s[0...t-1] = s[i-t...i-1]
比如 0123 4 0123 5 ,next[9] = 4.
结论:len - next[len] 为最小覆盖子串。
Poj3461 Oulipo
题意:给出两个串,问第二个串在第一个串中出现的次数
/* *********************************************** Author : 一个西瓜 Mail : 879447570@qq.com Created Time : 2015-04-07 16:24:21 Problem : Oulipo ************************************************ */ #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; #define INF 1000000000 //typedef __int64 LL; const int maxn = 11111; int next[maxn]; char str[maxn]; char str1[maxn*100]; void get_next(char *s) { next[0] = -1; int j = 0 ;int k = -1; int len = strlen(s); while(j<len){ if(k==-1||s[j]==s[k]){ j++;k++;next[j] = k; } else k = next[k]; } } int gao(char *s1,char *s2) { int ans = 0; int len1 = strlen(s1);int len2 =strlen(s2); int j = -1;int k = -1; while(j<len2){ if(k==-1||s1[k]==s2[j]){ j++;k++; //printf("%d %d\n",j,k); } else k = next[k]; if(k==len1){ ans++;k = next[k]; } } return ans; } int main() { int T; cin>>T; while(T--){ cin>>str; cin>>str1; get_next(str); int k = gao(str,str1); cout<<k<<endl; } return 0; }
Poj1961 Period
就用到上面那个结论了
/* *********************************************** Author : 一个西瓜 Mail : 879447570@qq.com Created Time : 2015-04-07 17:50:15 Problem : Period ************************************************ */ #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; #define INF 1000000000 //typedef __int64 LL; const int maxn = 1111111; int next[maxn]; char str[maxn]; void get_next(char *s) { int len =strlen(s); int j = 0;int k = -1; next[0] = -1; while(j<len){ if(k==-1||s[j]==s[k]){ j++;k++; next[j] = k; } else k = next[k]; } } int main() { int Icase = 0 ; int n; while(scanf("%d",&n)&&n){ if(Icase) cout<<endl; printf("Test case #%d\n",++Icase); scanf("%s",str); get_next(str); int len = strlen(str); for(int i = 1;i<len;i++){ int t = i+1; if(t%(t - next[t])==0&&(t/(t-next[t])!=1)){ printf("%d %d\n",t,t/(t - next[t])); } } } return 0; }
Poj2752 Seek the Name, Seek the Fame
给出一个串,问哪些既是前缀,又是后缀。
next数组不就是,到当前串的第i个位置,既是这个子串的前缀又是后缀的最长前缀么。迭代下去求就行了。
/* *********************************************** Author : 一个西瓜 Mail : 879447570@qq.com Created Time : 2015-04-07 17:28:12 Problem : Seek the Name, Seek the Fame ************************************************ */ #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; #define INF 1000000000 //typedef __int64 LL; const int maxn = 4*1e5 +10; int next[maxn]; char str[maxn]; void get_next(char *s) { next[0] = -1; int len =strlen(s); int j = 0 ;int k = -1; while(j<len){ if(k==-1||s[j]==s[k]){ j++;k++;next[j] = k; } else k = next[k]; } } vector<int> q; int main() { while(scanf("%s",str)!=EOF){ get_next(str); q.clear(); int k = strlen(str); q.push_back(k); k = next[k]; while(k){ q.push_back(k); k = next[k]; } for(int i = q.size() - 1;i>=0;i--){ printf("%d ",q[i]); } cout<<endl; } return 0; }
Poj2406 Power Strings
和1961一样的。
/* *********************************************** Author : 一个西瓜 Mail : 879447570@qq.com Created Time : 2015-04-07 17:50:40 Problem : Power Strings ************************************************ */ #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; #define INF 1000000000 //typedef __int64 LL; const int maxn = 1e6+10; char str[maxn]; int next[maxn]; void get_next(char *s) { int len =strlen(s); int j = 0 ;int k = -1; next[0] = -1; while(j<len){ if(k==-1||s[j]==s[k]){ j++;k++; next[j] = k; } else k = next[k]; } } int main() { while(cin>>str){ if(str[0]=='.') break; get_next(str); int len = strlen(str); if(len%(len-next[len])==0) cout<<len / (len - next[len])<<endl; else cout<<1<<endl; } return 0; }