bzoj4641 基因改造 KMP / hash
依稀记得,$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 namespace std; 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; }
喵喵喵?喵喵喵! 喵喵喵......