1 字符串 Hash
const ll mod[3] = {900000011, 998244353, 1000000007}; const ll bas[3] = {4493, 8111, 8527}; // you can choose your bases and modulos char s[S]; ll pw[3][S], Hash[3][S]; inline ll getHash(int id, int L, int R){ // str[L..R-1] ll J = (Hash[id][R] - Hash[id][L] * pw[id][R - L]) % mod[id]; return J < 0 ? J + mod[id] : J; } // following is the pretreatment ll *f, *g; for(j = 0; j < 3; j++){ f = Hash[j]; f[0] = 0; g = pw[j]; g[0] = 1; for(i = 0; i < n; i++){ f[i + 1] = (f[i] * bas[j] + (s[i] - 'a')) % mod[j]; g[i + 1] = g[i] * bas[j] % mod[j]; } }
2 KMP 模式匹配
// pretreatment (border) for (j = *f = -1, i = 1; i < n; f[++i] = ++j) for (; ~j && s[j] != s[i]; j = f[j]); // KMP for (j = i = 0; i < _n; ++i) { for (; ~j && s[j] != m[i]; j = f[j]); if (++j == n) printf("%d ", i - s_n + 2); }
3 字典树
void append(char *s){ char *p = s; int t = 1, id; // t = 0 is also OK for(; *p; ++p){ id = *p - 97; t = d[t][id] ? d[t][id] : (d[t][id] = ++V); } ++val[t]; } // the process of matching is just like going on a DFA, so omit it.
4 Aho-Corasick 自动机
void build(){ int h, ta = 1, i, t, id; que[0] = 1; f[1] = 0; for(h = 0; h < ta; ++h) for(i = que[h], id = 0; id < 26; ++id){ // 26 is the size of char-set t = (f[i] ? d[f[i]][id] : 1); // 1 or 0 depend on the root of trie int &u = d[i][id]; if(!u) {u = t; continue;} f[u] = t; val[u] |= val[t]; que[ta++] = u; la[u] = (v[t] ? t : la[t]); } }
5 后缀数组 (倍增构造) 与最长公共前缀
struct LCP { int n, *sa, *rnk, *st[LN]; LCP () : n(0), sa(NULL), rnk(NULL) {memset(st, 0, sizeof st);} ~LCP () { if (sa) delete [] sa; if (rnk) delete [] rnk; for (int i = 0; i < LN; ++i) if (st[i]) delete [] st[i]; } void construct(const char *s) { int i, j, k, m = 256, p, limit; n = strlen(s); int *x = new int[n + 1], *y = new int[n + 1], *buf = new int[max(n, m)], *f, *g = new int[n + 1]; auto cmp = [this] (const int *a, const int u, const int v, const int l) {return a[u] == a[v] && (u + l >= n ? 0 : a[u + l]) == (v + l >= n ? 0 : a[v + l]);}; if (sa) delete [] sa; sa = new int[n]; if (rnk) delete [] rnk; for (i = 0; i < LN; ++i) if (st[i]) delete [] st[i], st[i] = 0; for (i = 0; i < n; ++i) sa[i] = i, x[i] = (unsigned char)s[i]; std::sort(sa, sa + n, [s] (const int u, const int v) {return (unsigned char)s[u] < (unsigned char)s[v];}); for (j = 1; j < n; j <<= 1, m = ++p) { std::iota(y, y + j, n - j), p = j; for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j; memset(buf, 0, m << 2); for (i = 0; i < n; ++i) ++buf[ x[y[i]] ]; for (i = 1; i < m; ++i) buf[i] += buf[i - 1]; for (i = n - 1; i >= 0; --i) sa[ --buf[ x[y[i]] ] ] = y[i]; std::swap(x, y); x[*sa] = p = 1, x[n] = 0; for (i = 1; i < n; ++i) x[sa[i]] = (cmp(y, sa[i - 1], sa[i], j) ? p : ++p); if (p >= n) break; } if (rnk = x, n == 1) *x = 0; else for (i = 0; i < n; ++i) --x[i]; delete [] buf, delete [] y; for (p = i = 0; i < n; ++i) { if (p && --p, !x[i]) continue; for (j = sa[x[i] - 1], limit = n - max(i, j); p < limit && s[i + p] == s[j + p]; ++p); g[ x[i] - 1 ] = p; } *st = g, k = n - 1; for (j = 0; 1 << (j + 1) < n; ++j) { k -= 1 << j, f = g, g = st[j + 1] = new int[k + 1]; for (i = 0; i < k; ++i) g[i] = min(f[i], f[i + (1 << j)]); } } inline int operator () (const int u, const int v) { assert((unsigned)u < (unsigned)n && (unsigned)v < (unsigned)n); if (u == v) return n - u; int L, R, c; std::tie(L, R) = std::minmax(rnk[u], rnk[v]), c = lg2(R - L); return min(st[c][L], st[c][R - (1 << c)]); } };
6 后缀自动机
#define q d[p][x] int extend(int x) { for (p = np, val[np = ++cnt] = val[p] + 1; p && !q; q = np, p = pa[p]); if (!p) pa[np] = 1; else if (val[p] + 1 == val[q]) pa[np] = q; else { int nq = ++cnt; val[nq] = val[p] + 1, memcpy(d[nq], d[q], 104); pa[nq] = pa[q], pa[np] = pa[q] = nq; for (int Q = q; p && q == Q; q = nq, p = pa[p]); } return f[np] = 1, np; } #undef q 7 根据后缀自动机构造后缀树 void build() { int i, j, c; used[1] = true; for (i = cnt; i; --i) if (~pos[i]) for (j = i; !used[j]; j = pa[j]) c = pos[j] - val[pa[j]], pos[pa[j]] = pos[j], child[pa[j]][int(s[c])] = j, used[j] = true; // dfs(1); }
8 Z 算法
void Z() { int i, Max = 0, M = 0; for (i = 1; i < n; ++i) { z[i] = (i < Max ? std::min(z[i - M], Max - i) : 0); for (; s[z[i]] == s[i + z[i]]; ++z[i]); if (i + z[i] > Max) Max = i + z[i], M = i; } }
9 Manacher 回文串
void Manacher() { int n = 2, i, Max = 0, M = 0; t[0] = 2, t[1] = 1; for (i = 0; i < S; ++i) t[n++] = s[i], t[n++] = 1; t[n++] = 3; for (i = 0; i < n; ++i){ f[i] = (i < Max ? std::min(f[M * 2 - i], Max - i) : 1); for(; t[i + f[i]] == t[i - f[i]]; ++f[i]); if (i + f[i] > Max) Max = i + f[i], M = i; } }
10 回文自动机
int get_fail(int x) {for (; ptr[~val[x]] != *ptr; x = fail[x]); return x;} int extend(int x) { int &q = d[p = get_fail(p)][x]; if (!q) fail[++cnt] = d[get_fail(fail[p])][x], val[q = cnt] = val[p] + 2; return p = q; } val[1] = -1, p = 0, *fail = cnt = 1;
11 多串后缀自动机 / 广义后缀自动机
#define q d[p][x] #define try_split(v) { \ if (val[p] + 1 == val[q]) v = q; \ else { \ int nq = ++cnt; \ val[nq] = val[p] + 1, memcpy(d[nq], d[q], 104); \ pa[nq] = pa[q], v = pa[q] = nq; \ for (int Q = q; p && q == Q; q = nq, p = pa[p]); \ } \ } int extend(int x) { if (p = np, q) try_split(np) else { for (val[np = ++cnt] = val[p] + 1; p && !q; q = np, p = pa[p]); if (p) try_split(pa[np]) else pa[np] = 1; } return np; } #undef q