kuangbin专题十六:KMP & 扩展KMP & Manacher
思路:kmp模板。
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> using namespace std; const int maxm = 1e4 + 5; const int maxn = 1e6 + 5; int T, n, m; int a[maxn], b[maxm]; int Next[maxm]; void genNext(){ Next[0] = -1; int j = -1; for(int i = 1; i < m; i++){ while(j != -1 && b[i] != b[j+1]) j = Next[j]; if(b[i] == b[j+1]) j++; Next[i] = j; } } int kmp(){ int j = -1; for(int i = 0; i < n; i++){ while(j != -1 && a[i] != b[j+1]) j = Next[j]; if(a[i] == b[j+1]) j++; if(j == m-1) return i - m + 2; } return -1; } int main(){ scanf("%d", &T); while(T--) { scanf("%d%d", &n, &m); for(int i = 0; i < n; i++) scanf("%d", a+i); for(int i = 0; i < m; i++) scanf("%d", b+i); genNext(); printf("%d\n", kmp()); } return 0; }
思路:kmp模板。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int maxn = 1e6 + 5; const int maxm = 1e4 + 5; char W[maxm], T[maxn]; int Next[maxm]; int Tn, n, m; void genNext() { Next[0] = -1; int j = -1; for (int i = 1; i < m; i++){ while(j != -1 && W[i] != W[j+1]) j = Next[j]; if(W[i] == W[j+1]) j++; Next[i] = j; } } int kmp(){ int j = -1, res = 0; for(int i = 0; i < n; i++){ while(j != -1 && T[i] != W[j+1]) j = Next[j]; if(T[i] == W[j+1]) j++; if (j == m-1) res++, j = Next[j]; } return res; } int main(){ scanf("%d", &Tn); while(Tn--){ scanf("%s", W); scanf("%s", T); m = strlen(W), n = strlen(T); genNext(); printf("%d\n", kmp()); } return 0; }
思路:kmp模板题。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int maxn = 1e3 + 5; char tile[maxn], pattern[maxn]; int Next[maxn]; int n, m; void genNext() { int j = -1; Next[0] = -1; for(int i = 1; i < m; i++){ while(j != - 1 && pattern[i] != pattern[j+1]) j = Next[j]; if (pattern[i] == pattern[j + 1]) j++; Next[i] = j; } } int kmp(){ genNext(); int j = -1, res = 0; for (int i = 0; i < n; i++){ while(j != -1 && tile[i] != pattern[j+1]) j = Next[j]; if (tile[i] == pattern[j+1]) j++; if(j == m-1) res++, j = -1; } return res; } int main(){ while(scanf("%s", tile) && tile[0] != '#'){ scanf("%s", pattern); n = strlen(tile), m = strlen(pattern); printf("%d\n", kmp()); } return 0; }
思路:题目没看,以前代码。
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int maxn = 1e5+5; char T[maxn]; int tlen; int Next[maxn]; void getNext(){ int i=0, j=-1; Next[0] = -1; while(i < tlen){ if(j==-1 || T[i]==T[j]) Next[++i] = ++j; else j = Next[j]; } } int main(){ int t; scanf("%d", &t); while(t--){ scanf("%s", T); tlen = strlen(T); getNext(); int length = tlen - Next[tlen]; if(tlen != length && tlen%length==0) printf("0\n"); else{ int add = length - Next[tlen] % length; printf("%d\n", add); } } return 0; }
思路:利用next数组寻找循环子列长度。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int maxn = 1e6 + 5; int n; char s[maxn]; int Next[maxn]; void genNext(){ int j = -1; Next[0] = -1; for(int i = 1; i < n; i++){ while(j != -1 && s[i] != s[j+1]) j = Next[j]; if(s[i] == s[j+1]) j++; Next[i] = j; } } int main(){ int T = 0; while(scanf("%d", &n) && n){ scanf("%s", s); genNext(); printf("Test case #%d\n", ++T); for(int i = 1; i < n; i++) if(Next[i] >= i/2 && (i+1)%(i-Next[i])==0) printf("%d %d\n", i+1, (i+1)/(i-Next[i])); printf("\n"); } return 0; }
思路:同前一题。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int maxn = 1e6 + 5; int n; char s[maxn]; int Next[maxn]; void genNext(){ int j = Next[0] = -1; for(int i = 1; i < n; i++){ while(j != -1 && s[i] != s[j+1]) j = Next[j]; if(s[i] == s[j+1]) j++; Next[i] = j; } } int main(){ while(scanf("%s", s) && s[0] != '.'){ n = strlen(s); genNext(); if(n % (n-1 - Next[n-1]) == 0) printf("%d\n", n / (n - 1 - Next[n-1])); else printf("1\n"); } return 0; }
POJ2752 Seek the Name, Seek the Fame
思路:扩展kmp。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int maxn = 4e5 + 5; int n; char s[maxn]; int z[maxn]; void exKMP(){ memset(z, 0, sizeof(z)); for(int i = 1, l = 0, r = 0; i < n; i++){ if(i <= r) z[i] = min(r - i + 1, z[i - l]); while(i + z[i] < n && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > r) l = i, r = i + z[i] - 1; } } int main(){ while(~scanf("%s", s)){ n = strlen(s); exKMP(); for (int i = n - 1; i > 0; i--) if (i + z[i] == n) printf("%d ", z[i]); printf("%d\n", n); } return 0; }
HDU2594 Simpsons’ Hidden Talents
思路:扩展kmp,注意最长后缀取值范围。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<vector> using namespace std; const int maxn = 2 * 50000 + 5; char s[maxn]; int z[maxn]; int m, n; void extkmp(){ memset(z, 0, sizeof(z)); for(int i = 1, l = 0, r = 0; i < m; i++){ if(i <= r) z[i] = min(r - i + 1, z[i - l]); while(i + z[i] < m && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > r) l = i, r = i + z[i] - 1; } } int main(){ while(~scanf("%s", s)){ n = strlen(s); scanf("%s", s + n); m = strlen(s); extkmp(); int res = 0; for(int i = max(n, m-n); i < m; i++){ if(i + z[i] == m){ res = i; break; } } if(res) printf("%s %d\n", s+res, m-res); else printf("0\n"); } return 0; }
思路:莫名其妙的wa了两次。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<vector> using namespace std; const int maxn = 2e5 + 5; const int mod = 10007; char s[maxn]; int Next[maxn]; int dp[maxn]; int n; void rev(){ for(int i = 0; i < n / 2; i++){ char t = s[i]; s[i] = s[n-i-1]; s[n-i-1] = t; } } void genNext(){ memset(Next, 0, sizeof(Next)); int j; j = Next[0] = -1; for(int i = 1; i < n; i++){ while(j != -1 && s[i] != s[j+1]) j = Next[j]; if(s[i] == s[j+1]) j++; Next[i] = j; } } int main(){ int t; scanf("%d", &t); while(t--){ scanf("%d%s", &n, s); genNext(); memset(dp, 0, sizeof(dp)); int ans = 0; for(int i = 0; i < n; i++){ dp[i] = (dp[Next[i]] + 1) % mod; ans = (dp[i] + ans) % mod; } printf("%d\n", ans); } return 0; }
思路:题目太长不看。