AC自动机

来源:互联网 发布:屏幕碎裂的软件 编辑:程序博客网 时间:2024/04/29 13:29

md,弄这个原理就弄了好久。。
还是得多写写,不然又忘了。
这是模板题<–点它

#include<iostream>#include<cstdio>#include<cstring>#define mk(a) memset(a,0,sizeof(a))using namespace std;const int N=1001000;struct ACMachine{     int s[N][26],fail[N],w[N];//s是trie数组,fail是指针数组,w是字符的个数     char S[N<<1];     bool ex[N];//ex表示是否是单词的节点     int dl[N];//以bfs的序列进行遍历     int n,tot,ans;     int newnode()     {         fail[++tot]=0;         ex[tot]=0;         for(int i=0;i<26;i++)s[tot][i]=0;         return tot;     }     void insert(char *a)     {         int len=strlen(a),u=1;         for(int i=0,j=a[i]-'a';i<len;j=a[++i]-'a')             u=s[u][j]?s[u][j]:s[u][j]=newnode();         w[u]++;         ex[u]=1;     }     void got(int p)     {         for(int i=0;i<26;i++)         {             int tmp=s[fail[p]][i];             if(s[p][i])fail[s[p][i]]=tmp,ex[s[p][i]]|=ex[tmp];             else s[p][i]=tmp;         }     }     void getfail()//bfs序     {         int u=0,d=0,p;         for(dl[++u]=1;u>d;got(p))         {             p=dl[++d];             for(int i=0;i<26;i++)                 if(s[p][i])dl[++u]=s[p][i];         }     }     void init()     {        tot=1;        mk(w); mk(ex); mk(fail); mk(s);        fail[1]=0;        for(int i=0;i<26;i++)s[0][i]=1;     }     void read()     {         char a[20];         scanf("%d",&n);         getchar();         for(int i=1;i<=n;i++)             gets(a),insert(a);         gets(S);     }     void runarun()     {         int len=strlen(S),u=1;         for(int i=0,j=S[i]-'a';i<len;j=S[++i]-'a')         {            if(j>=0 && j<26)u=s[u][j];            else {u=1;continue;}//          cout<<u<<" "<<w[u]<<" "<<ex[u]<<endl;            for(int p=u; p>1 && ex[p];p=fail[p])ans+=w[p],w[p]=0;         }     }     void work()     {         init();         read();         getfail();//失败指针         ans=0;         runarun();         printf("%d\n",ans);     }}d;int main(){    int T;    scanf("%d",&T);    while(T--)d.work();    return 0;}
0 1