AC自动机

来源:互联网 发布:我是歌手有网络直播吗 编辑:程序博客网 时间:2024/05/29 09:21

AC自动机:简单版
询问每个字符串是否出现过
为了压缩时间,我们当碰到一个ed结点的时候,
如果该结点没有访问过,我们就按照fail跳一遍
如果该结点之前统计过,我们就不用顺着fail指针再统计了

//这里写代码片#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int N=1000005;int n,ch[N][26],tot=0,word[N];char s[N],w[N]; bool ed[N];int Q[N],tou,wei,cnt[N],fail[N];void build(int bh){    int len=strlen(w);    int now=0;    for (int i=0;i<len;i++)    {        int x=w[i]-'a';        if (!ch[now][x]) ch[now][x]=++tot;        now=ch[now][x];    }    ed[now]=1;    word[bh]=now;}void makefail(){    tou=wei=0;    for (int i=0;i<26;i++)        if (ch[0][i])            Q[++wei]=ch[0][i];    while (tou<wei)    {        int now=Q[++tou];        for (int i=0;i<26;i++)        {            if (!ch[now][i])            {                ch[now][i]=ch[fail[now]][i];                continue;            }            Q[++wei]=ch[now][i];            fail[ch[now][i]]=ch[fail[now]][i];        }    }}void solve(){    memset(cnt,0,sizeof(cnt));    int len=strlen(s);    int now=0,ans=0;    for (int i=0;i<len;i++)    {        int x=s[i]-'a';        while (now&&!ch[now][x]) now=fail[now];        now=ch[now][x];        if (ed[now]&&cnt[now]==0)         //cnt=0 第一次访问         {            cnt[now]++;             int f=now;            while (f&&cnt[f]==0)            {                f=fail[f];                 cnt[f]++;            }        }    }    for (int i=1;i<=n;i++) if (cnt[word[i]]) ans++;    printf("%d",ans);}int main(){    scanf("%d",&n);    for (int i=1;i<=n;i++)    {        scanf("%s",w);        build(i);    }    makefail();    scanf("%s",s);    solve();    return 0;}