【后缀自动机】51nod 淋漓尽致子串
题意:最大周期串有多少个,子串不算。
思路:建好SAM后,fail和next跳,删除前缀相同和后缀相同即可
代码:
#include <cstdio> #include <cstring> #include <vector> #include <map> #include <string> #include <algorithm> using namespace std; const int MAX_N = 200007; typedef unsigned long long ll; struct SAM { int val[MAX_N], fa[MAX_N], c[26][MAX_N]; int tot, last; int which[MAX_N]; //该节点的字符 inline int newNode(int step) { val[++tot] = step; fa[tot] = 0; for (int i = 0; i < 26; ++i) c[i][tot] = 0; return tot; } inline void extend(int k) { int p = last; int np = newNode(val[last] + 1); which[np] = k; while (p && !c[k][p]) c[k][p] = np, p = fa[p]; if (!p) fa[np] = 1; else { int q = c[k][p]; if (val[q] == val[p] + 1) fa[np] = q; else { int nq = newNode(val[p] + 1); which[nq] = k; for (int i = 0; i < 26; ++i) c[i][nq] = c[i][q]; fa[nq] = fa[q]; fa[q] = fa[np] = nq; while (p && c[k][p] == q) c[k][p] = nq, p = fa[p]; } } last = np; } inline int add(int k) { extend(k); } inline void init() { tot = 0; last = newNode(0); } } suf; char A[MAX_N>>1], B[MAX_N>>1]; int id[MAX_N], cnt[MAX_N], C[MAX_N]; int main() { scanf("%s", B); suf.init(); for (int i = 0; B[i]; ++i) suf.add(B[i] - 'a'); int len = strlen(B); for (int i = 1; i <= suf.tot; ++i) ++C[suf.val[i]]; for (int i = 1; i <= len; ++i) C[i] += C[i - 1]; for (int i = 1; i <= suf.tot; ++i) id[C[suf.val[i]]--] = i; int j = 1; for (int i = 0; i < len; ++i) { ++cnt[suf.c[B[i] - 'a'][j]]; j = suf.c[B[i] - 'a'][j]; } for (int i = suf.tot; i > 0; --i) { int d = id[i]; cnt[suf.fa[d]] += cnt[d]; } for (int i = 1; i <= suf.tot; ++i) { int d = id[i]; for (int j = 0; j < 26; ++j) { if (suf.c[j][d] == 0) continue; if (cnt[suf.c[j][d]] > 1) { cnt[d] = 1; break; } } while (d && cnt[suf.fa[d]] > 1) d = suf.fa[d], cnt[suf.fa[d]] = 1; } int ans = 0; for (int i = suf.tot; i > 1; --i) { if (cnt[i] > 1) ++ans; } printf("%d\n", ans); return 0; }