bzoj4641 基因改造 KMP / hash
阿新 • • 發佈:2018-11-12
依稀記得,$NOIP$之前的我是如此的弱小....
完全不會$KMP$的寫法,只會暴力$hash$....
大體思路為把一個串的雜湊值拆成$26$個字母的位權
即$hash(S) = \sum\limits_{a} a * \sum w^i * [s[i] == a]$
通過記錄每個字母第一次出現的位置,用$26$的時間來確定$f$是什麼
然後通過確定的$f$計算出$f$是正確的時候的$hash$值,和原串的$hash$值比較
複雜度$O(26n)$
自然取模....
#include <cstdio> #include <cstring> #include<iostream> #include <algorithm> namespace remoon { #define ri register int #define ll long long #define ull unsigned long long #define rep(io, st, ed) for(ri io = st; io <= ed; io ++) #define drep(io, ed, st) for(ri io = ed; io >= st; io --) } using namespacestd; using namespace remoon; #define sid 500050 char s[2005000], t[sid]; int n, m, tim, f[200]; int num[200], vis[200], nxt[200], tot; ull val[200], wei[sid]; ull seed = 19260817; inline void Init() { wei[0] = 1; rep(i, 1, m) wei[i] = wei[i - 1] * seed; rep(i, 1, m) { int le = t[i];if(!vis[le]) nxt[++ tot] = i, vis[le] = 1; val[le] += wei[m - i]; } tim ++; } inline void Solve() { ull now = 0, tval = 0; rep(i, 1, m) now += s[i] * wei[m - i]; rep(i, m, n) { tim ++; int flag = 0; rep(j, 1, tot) { int v = s[i - m + nxt[j]]; if(vis[v] == tim) { flag = 1; break; } if(vis[v] != tim) vis[v] = tim; f[j] = v; } if(!flag) { tval = 0; rep(j, 1, tot) tval += f[j] * val[t[nxt[j]]]; if(tval == now) write(i - m + 1); } now -= s[i - m + 1] * wei[m - 1]; now *= seed; now += s[i + 1]; } } int main() { scanf("%s", s + 1); n = strlen(s + 1); scanf("%s", t + 1); m = strlen(t + 1); Init(); Solve(); return 0; }
現在我明白了$KMP$是非常偉大的演算法....
對於此題而言,考慮每個字元的上一個字元離當前字元的距離,這可以成為一個新串
然後比對新串即可
特別的,如果上一個字元出現的位置超過了匹配長度,那麼我們也要視作合法
但是,我們發現這種匹配滿足有前效性,沒有後效性,因此可以用$KMP$
複雜度$O(n)$,十分的優秀
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> namespace remoon { #define ri register int #define rep(io, st, ed) for(ri io = st; io <= ed; io ++) #define drep(io, ed, st) for(ri io = ed; io >= st; io --) } using namespace std; using namespace remoon; const int sid = 1005000; int n, m; char s[sid], t[sid]; int lst[200], S[sid], T[sid], nxt[sid]; inline bool match(int x, int y) { if(y > m) return 0; if(x == T[y]) return 1; if(!T[y] && x >= y) return 1; return 0; } int main() { scanf("%s", s + 1); scanf("%s", t + 1); n = strlen(s + 1); m = strlen(t + 1); rep(i, 1, n) { S[i] = lst[s[i]] ? i - lst[s[i]] : 0; lst[s[i]] = i; } memset(lst, 0, sizeof(lst)); rep(i, 1, m) { T[i] = lst[t[i]] ? i - lst[t[i]] : 0; lst[t[i]] = i; } for(ri i = 2, j = 0; i <= m; i ++) { while(j && !match(T[i], j + 1)) j = nxt[j]; if(match(T[i], j + 1)) j ++; nxt[i] = j; } for(ri i = 1, j = 0; i <= n; i ++) { while(j && !match(S[i], j + 1)) j = nxt[j]; if(match(S[i], j + 1)) j ++; if(j == m) printf("%d\n", i - m + 1); } return 0; }