题目大意:给你$n$个字符串,对每个字符串求出只在这个字符串中出现的字串的个数
题解:先建广义$SAM$,然后对每个点统计一下它的子树中是不是都是在同一个字符串中的,是的话,就把这个点标成这一个字符串,计算贡献
卡点:无
C++ Code:
#include <algorithm> #include <cstdio> #include <cstring> #define maxn 100010 long long ans[maxn]; namespace SAM { #define N (maxn << 1) int R[N], fail[N], nxt[N][26]; int lst = 1, idx = 1, bel[N]; void append(int ch, int tg) { int p = lst, np = lst = ++idx; R[np] = R[p] + 1, bel[np] = tg; for (; p && !nxt[p][ch]; p = fail[p]) nxt[p][ch] = np; if (!p) fail[np] = 1; else { int q = nxt[p][ch]; if (R[p] + 1 == R[q]) fail[np] = q; else { int nq = ++idx; fail[nq] = fail[q], R[nq] = R[p] + 1, fail[q] = fail[np] = nq; std::copy(nxt[q], nxt[q] + 26, nxt[nq]); for (; p && nxt[p][ch] == q; p = fail[p]) nxt[p][ch] = nq; } } } int head[N], cnt; struct Edge { int to, nxt; } e[N]; inline void addedge(int a, int b) { e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt; } void dfs(int u) { for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; dfs(v); if (~bel[v]) { if (!bel[u]) bel[u] = bel[v]; else if (bel[u] != bel[v]) bel[u] = -1; } else bel[u] = -1; } } void work() { for (int i = 2; i <= idx; i++) addedge(fail[i], i); dfs(1); for (int i = 2; i <= idx; i++) if (bel[i] != -1) ans[bel[i]] += R[i] - R[fail[i]]; } #undef N } int n; char s[maxn]; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%s", s); SAM::lst = 1; for (register char *ch = s; *ch; ++ch) SAM::append(*ch - 'a', i); } SAM::work(); for (int i = 1; i <= n; i++) printf("%lld ", ans[i]); return 0; }