题目大意:有$n$个字符串,求每个字符串在所有字符串中出现的次数
题解:$AC$自动机,每个节点被经过时$sz$加一,每一个字符串出现次数为其$fail$树子树$sz$和
卡点:$AC$自动机根节点为$1$,没有在$build$的时候将所有空的$nxt[1][i]$赋值为$1$
C++ Code:
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <queue>
const int maxn = 1e6 + 10;
std::string s;
int n, ret[210];
namespace AC {
int nxt[maxn][26], fail[maxn], idx = 1, cnt[maxn];
int insert(std::string s) {
int p = 1;
for (char ch : s) {
if (nxt[p][ch - 'a']) p = nxt[p][ch - 'a'];
else p = nxt[p][ch - 'a'] = ++idx;
++cnt[p];
}
return p;
}
void build() {
static std::queue<int> q;
for (int i = 0; i < 26; ++i)
if (nxt[1][i]) fail[nxt[1][i]] = 1, q.push(nxt[1][i]);
else nxt[1][i] = 1;
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = 0; i < 26; ++i)
if (nxt[u][i]) fail[nxt[u][i]] = nxt[fail[u]][i], q.push(nxt[u][i]);
else nxt[u][i] = nxt[fail[u]][i];
}
}
int head[maxn], CNT;
struct Edge {
int to, nxt;
} e[maxn];
void addedge(int a, int b) {
e[++CNT] = (Edge) { b, head[a] }; head[a] = CNT;
}
void dfs(int u) {
for (int i = head[u], v; i; i = e[i].nxt) {
v = e[i].to;
dfs(v);
cnt[u] += cnt[v];
}
}
void solve() {
for (int i = 2; i <= idx; ++i) addedge(fail[i], i);
dfs(1);
}
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
std::cin >> n;
for (int i = 0; i < n; ++i) {
std::cin >> s;
ret[i] = AC::insert(s);
}
AC::build(), AC::solve();
for (int i = 0; i < n; ++i) std::cout << AC::cnt[ret[i]] << '\n';
return 0;
}