AC自动机
基于trie和kmp
fail指针
学习过程:
oi wiki理解思路,听y总讲代码
模板一:acwing代码过不去,是要在求答案时跳fail的时候,打标记,每个点只走一次
模板二:连trie图
模板三:拓扑序求答案,拓扑排序不用单独写,build里顺手求一下就可以
阿狸打字机:理解fail树的思路,可以通过fail树子树概念理解包含子串的节点,顺便融合dfn序和树状数组(写一周才过)
S2025谐音替换:我靠这也太简单了!
模板:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+10;
int n, tr[N][30], cnt[N], res[N], nxt[N], idx, c[N], r[N], vis[N];
string s;
void insert(int d){
int p = 0;
for(int i = 0; i < s.size(); i++){
int t = s[i]-'a';
if(!tr[p][t]) tr[p][t] = ++idx;
p = tr[p][t];
}
cnt[p]++;
c[d] = p;
}
void build(){
queue<int> q;
for(int i = 0; i < 26; i++) if(tr[0][i]) q.push(tr[0][i]);
while(q.size()){
int t = q.front();
q.pop();
for(int i = 0; i < 26; i++){
int p = tr[t][i];
if(!p) tr[t][i] = tr[nxt[t]][i];
else{
nxt[p] = tr[nxt[t]][i];
q.push(p);
}
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> s;
insert(i);
}
build();
cin >> s;
for(int i = 0, j = 0; i < s.size(); i++){
int t = s[i]-'a';
j = tr[j][t];
int p = j;
res[p]++;
}
queue<int> q;
for(int i = 1; i <= idx; i++) r[nxt[i]] ++;
for(int i = 1; i <= idx; i++) if(!r[i]) q.push(i);
//拓扑排序,其实不用在外面单独写
while(q.size()){
int t = q.front();
q.pop();
r[nxt[t]]--;
res[nxt[t]] += res[t];
if(!r[nxt[t]]) q.push(nxt[t]);
}
for(int i = 1; i <= n; i++){
cout << res[c[i]] << '\n';
}
return 0;
}

浙公网安备 33010602011771号