AC自动机
AC 自动机可以看做是一个 trie 树与 KMP 结合的一个东西。其解决的问题是 KMP 的升级版:多模式串匹配。
P3808 AC 自动机(简单版)
正常的多模式串匹配,AC 自动机的入门题。
由于模式串不少,因此我们先考虑将所有模式串插入一个 trie 树里。
然后我们考虑像 KMP 一样对于 trie 上的每一个点所对应的根到这个点所对应的字符串的失配指针。
由于每一个节点的失配指针都要靠其父亲来求,因此我们直接在 trie 树上 bfs。根据定义不难发现显然有 \(fail_v=ch_{fail_u,s_v}\)。其中 \(v\) 是 tire 树上 \(u\) 的儿子。
需要注意的是,如果 \(u\) 没有某种字符 \(s\) 的儿子,我们将 \(ch_{u,s}\gets ch_{fail_u,s}\) 是等效的。这样做是为了保证可以从一些匹配串计算到另外一些匹配串上。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+7;
int n,ch[N][26],idcnt,cnt[N],fail[N];
void insert(string s){
int len=s.length(),u=0;
for(int i=0;i<len;i++){
if(!ch[u][s[i]-'a']) ch[u][s[i]-'a']=++idcnt;
u=ch[u][s[i]-'a'];
}
cnt[u]++;
}
void AC(){
queue <int> q;
fail[0]=0;int u=0;for(int i=0;i<26;i++) if(ch[u][i]) fail[ch[u][i]]=0,q.push(ch[u][i]);
while(!q.empty()){
u=q.front();q.pop();
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];//这句话是为了保证可以走子串
}
}
int query(string t){
int u=0,len=t.length(),ans=0;
for(int i=0;i<len;i++){
u=ch[u][t[i]-'a'];int v=u;
while(v&&cnt[v]!=-1){
ans+=cnt[v];cnt[v]=-1;v=fail[v];
}
}
return ans;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){string s;cin>>s;insert(s);}
AC();string t;cin>>t;cout<<query(t);return 0;
}

浙公网安备 33010602011771号