{模板}AC自动机

来源:互联网 发布:京东数据罗盘供应商 编辑:程序博客网 时间:2024/05/21 10:01

先贴一个大白书的代码
来自这篇blog

//HDU2222#include <queue>    #include <cstdio> #include <cstring>#include <iostream> #include <algorithm>using namespace std;  const int N=500500;  struct ACautomachine{      int chd[N][26];//孩子节点编号    int cnt[N];//当前结点 表示字符串个数    int fail[N];//失配指针    int last[N],sz,ans;//题目需要      void init()      {          sz=1,ans=0;          memset(cnt,0,sizeof(cnt));          memset(fail,0,sizeof(fail));          memset(chd[0],0,sizeof(chd[0]));      }      void insert(char* p)//构建trie      {          int cur=0;          for(;*p;p++)          {              if(!chd[cur][*p-'a'])              {                  memset(chd[sz],0,sizeof(chd[sz]));                  chd[cur][*p-'a']=sz++;              }              cur=chd[cur][*p-'a'];          }          cnt[cur]++;      }      bool query(char* p)//题目需要    {          int cur=0;          for(;*p;p++)          {              if(!chd[cur][*p-'a']) break;              cur=chd[cur][*p-'a'];          }          return cnt[cur]&&(!(*p));      }      int getFail()      {          queue<int> q;          fail[0]=0;          for(int c=0;c<26;c++)          {              int u=chd[0][c];              if(u)              {                  fail[u]=0/*Null*/;                q.push(u);                 last[u]=0;              }          }          while(!q.empty())          {              int r=q.front();            q.pop();            for(int c=0;c<26;c++)              {                  int u=chd[r][c];                  if(!u)                {                    //直接指向 fail                     //也就是 把 trie树 的 chd[fail[r]][c]及其子孙 全部 “复制” 作r点的子孙                    chd[r][c]=chd[fail[r]][c];                    continue;                }                q.push(u);                  int v=fail[r];                 while(v&&!chd[v][c]) v=fail[v];                //1. 令指针为 fail[fa[u]]                //2. 若指针的一级儿子中存在一点(代表字符)与 u 相同                 //  则令fail[u] 指向 当前指针的该儿子                //3. 否则 指针指向 fail[指针] 并重复 2 操作、                //目的:使得当前点及其到根的路径(即一个字典串) 与 fail 和fail[fail]... 所代表字典串 后缀相同                // 从而实现重新匹配                fail[u]=chd[v][c];                  last[u]=cnt[fail[u]] ? fail[u] : last[fail[u]];              }          }      }      void solve(int j)  //题目需要    {          if(!j) return;          if(cnt[j])          {              ans+=cnt[j];              cnt[j]=0;          }          solve(last[j]);      }      void find(char* T)  //题目需要    {          int n=strlen(T),j=0;          getFail();          for(int i=0;i<n;i++)          {              j=chd[j][T[i]-'a'];              if(cnt[j]) solve(j);              else if(last[j]) solve(last[j]);          }      }  }ac;  int main()  {      int t,n;      char dic[100],str[1100000];      scanf("%d",&t);      while(t--)      {          ac.init();          scanf("%d",&n);          while(n--)          {              scanf("%s",dic);              ac.insert(dic);          }          scanf("%s",str);          ac.find(str);          printf("%d\n",ac.ans);      }      return 0;  }  

自己的
刚开始一点也不注意常数
TLE了好久啊[淚]

#include <ctime>#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define fo(i,x,y) for (int i=(x);i<=(y);++i)#define fd(i,x,y) for (int i=(x);i>=(y);--i)#define oo 2139062143using namespace std;typedef long long ll;typedef double db;const int N=501000,C=27;int T,n;int ans;char dic[55],str[1100000];struct AcAutoMation{    int d[N];    int chd[N][C];    int ot[N];    int fail[N],next[N],last[N];    int bz[N];    int sz;    void del(int x)    {        next[last[x]]=next[x],last[next[x]]=last[x];        bz[x]=1;    }    void init()    {        memset(bz,0,sizeof bz);        memset(chd[0],0,sizeof chd[0]);        memset(ot,0,sizeof ot);        memset(fail,0,sizeof fail);        sz=0;    }    void insert(char *p)    {        int tmp=0;        int len=strlen(p+1);        fo(i,1,len)        {            int now=p[i]-'a';            if(!chd[tmp][now])            {                   chd[tmp][now]=++sz;                memset(chd[sz],0,sizeof(chd[sz]));              }            tmp=chd[tmp][now];        }        ++ot[tmp];    }    void Getfail()    {        int tmp=0;        int hd=0,tl=0;        fo(i,0,25)        {            if(chd[0][i])             {                d[++tl]=chd[0][i];                fail[chd[0][i]]=0;                }        }        while(hd++<tl)        {            tmp=d[hd];            fo(i,0,25)            if(chd[tmp][i])            {                d[++tl]=chd[tmp][i];                int to=fail[tmp];                while(to!=0&&!chd[to][i]) to=fail[to];                fail[chd[tmp][i]]=chd[to][i];                next[chd[tmp][i]]=(ot[chd[tmp][i]])?(fail[chd[tmp][i]]):(next[fail[chd[tmp][i]]]);            }        }    }    void solve(char *p)    {        int tmp=0;        int len=strlen(p+1);        fo(i,1,len)        {            int now=p[i]-'a',to=tmp;            while(!chd[to][now]&&to) to=fail[to];            tmp=chd[to][now];            for (int pp=tmp;pp;pp=next[pp])            {                if(ot[pp])                {                     ans+=ot[pp],ot[pp]=0;                            }                           }            }    }}ac;int main(){    int TT=clock();    scanf("%d\n",&T);    while(T--)    {        ac.init();        scanf("%d\n",&n);        fo(i,1,n)        {            scanf("%s\n",dic+1);                ac.insert(dic);        }        ac.Getfail();        ans=0;        scanf("%s\n",str+1);        ac.solve(str);        printf("%d\n",ans);    }    return 0;}