其实原理我很久以前就会,一直没用,现来贴模板:
题意就是给n 个单词,然后给你一个文本串。问在这个文本串中出现这n个单词的数量。。。
用一个val[i]保存i节点结尾的单词个数就可以了。。
#include<bits/stdc++.h>
using namespace std;
const int M=60,N=1e6+10;
char s[N];
struct ac_auto
{
int ne[N][26],val[N],fail[N],sz;
void init()
{
memset(ne[0],0,sizeof(ne[0]));
sz=0;
}
void insert(char *s)//字典树部分
{
int o=0;
for(int i=0;s[i];++i)
{
int c=s[i]-'a';
if(ne[o][c]==0){
ne[o][c]=++sz;
val[sz]=0;
memset(ne[sz],0,sizeof(ne[sz]));
}
o=ne[o][c];
}
val[o]++;
}
void build()//bfs处理fail指针,指向深度小于自己的字符相同 最近的那个节点
{
queue<int>que;
for(int i=0;i<26;++i)
if(ne[0][i]){
que.push(ne[0][i]);
fail[ne[0][i]]=0;//第一层节点的fail指针指向根节点
}
while(que.size())
{
int o=que.front();que.pop();
for(int i=0;i<26;++i){
if(ne[o][i])
{
int v=ne[o][i];
int fa=fail[o];
while(fa&&!ne[fa][i]) fa=fail[fa];//如果当前节点没有 i 号儿子,继续跳fail指针,直到根或者有 i 号节点
fail[v]=ne[fa][i];
que.push(v);
}
}
}
}
int query(char *s)//查询 类字典树查询套 跳fail指针 保存答案
{
int o=0,ans=0;
for(int i=0;s[i];++i)
{
int c=s[i]-'a';
while(!ne[o][c]&&o) o=fail[o];
o=ne[o][c];
int tmp=o;
while(tmp)
{
ans+=val[tmp];
val[tmp]=0;
tmp=fail[tmp];
}
}
return ans;
}
}ac;
int main()
{
int _;cin>>_;while(_--)
{
int n;
scanf("%d",&n);
ac.init();
for(int i=1;i<=n;++i){
scanf("%s",s);
ac.insert(s);
}
ac.build();
scanf("%s",s);
printf("%d\n",ac.query(s));
}
}
















