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