题目链接

其实原理我很久以前就会,一直没用,现来贴模板:

题意就是给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));
    }
}