題目鏈接
https://www.luogu.org/problem/P5357
分析
相對於一般的AC自動機(或者常寫的Trie圖),
本題卡時主要在查詢時暴力向上跳 指針;
優化方法是按拓撲序更新答案,複雜度爲 ,
具體來說,按求 時BFS序的倒序依次更新每個節點對應答案。
注意模式串會有重複。
AC代碼
#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
using namespace std;
const int maxn = 2e5 + 5, maxs = 2e6 + 5;
int n, to[maxn], ans[maxn];
char str[maxs];
stack<int> st;
struct AC_Automaton {
int ch[maxn][26], end[maxn], cnt[maxn], fail[maxn], tot;
AC_Automaton() {
memset(ch[0], 0, sizeof(ch[0]));
memset(end, 0, sizeof(end));
memset(cnt, 0, sizeof(cnt));
memset(fail, 0, sizeof(fail));
tot = 0;
}
int add() {
++tot;
memset(ch[tot], 0, sizeof(ch[tot]));
return tot;
}
int insert(char* s, int id) {
int p = 0;
for (int i = 1; s[i]; ++i) {
if (!ch[p][s[i] - 'a']) ch[p][s[i] - 'a'] = add();
p = ch[p][s[i] - 'a'];
}
if (!end[p]) end[p] = id;
return end[p];
}
void build() {
queue<int> q;
for (int i = 0; i < 26; ++i)
if (ch[0][i]) q.push(ch[0][i]);
while (!q.empty()) {
int u = q.front();
q.pop(), st.push(u);
for (int i = 0; i < 26; ++i) {
if (ch[u][i])
fail[ch[u][i]] = ch[fail[u]][i], q.push(ch[u][i]);
else ch[u][i] = ch[fail[u]][i];
}
}
}
void query(char* s) {
int p = 0;
for (int i = 1; s[i]; ++i)
p = ch[p][s[i] - 'a'], ++cnt[p];
while (!st.empty()) {
int u = st.top();
st.pop();
ans[end[u]] = cnt[u];
cnt[fail[u]] += cnt[u];
}
}
} ac;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%s", str + 1);
to[i] = ac.insert(str, i);
}
ac.build();
scanf("%s", str + 1);
ac.query(str);
for (int i = 1; i <= n; ++i) printf("%d\n", ans[to[i]]);
return 0;
}