zoukankan      html  css  js  c++  java
  • AC自动机和KMP

    AC自动机存储一个字符串的集合,把他叫做T.用i(s)表示字符串s的代表节点. 用s(i)表示节点i的代表字符串.

    构建需要的时间是 $O(nc)$ 的,n为字符个数,c为字符集的大小.

    AC自动机的性质.

    1.从根到一个节点的路径是T中某些字串的前缀. (trie 基本性质)

    2.从一个节点到叶节点的路径是这个集合中某一个(如果T的元素不可重复)字串的后缀.(trie 基本性质)

    3.fail指针构成一棵fail树,树上父亲-儿子节点的关系为: 设父节点代表的字串为f,子节点为s,那么:

      f是s的后缀,但不一定是s的前缀. (fail树基本性质)

    4.如果s(i)是s(j)的后缀,那么在fail树上,i一定是j的祖先. (fail树基本性质)

     

    AC自动机的一个用处就是匹配.从trie的根节点(经过fail树边/trie树边)到点i的路径条数就是能匹配到点i的字符串个数.

    AC自动机的另一个用处是有了fail树以后,我们可以处理一些后缀相关的东西.此类题目大多具有自我匹配的特点,即用T中的字符串匹配T中的元素.


    AC USACO 2015 Feb. Gold T2 Censor

    一道模板题.....

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42  
     43 db eps=1e-20;
     44 inline bool feq(db a,db b)
     45 { return fabs(a-b)<eps; }
     46 
     47 template<typename Type>
     48 inline Type avg(const Type a,const Type b)
     49 { return a+((b-a)/2); }
     50 
     51 //==============================================================================
     52 //==============================================================================
     53 //==============================================================================
     54 //==============================================================================
     55 
     56 int n,m;
     57 char S[105000];
     58 char inp[105000];
     59 
     60 struct node
     61 {
     62     node*s[26];
     63     node*trans[26];
     64     node*f;
     65     node*p; //parent.
     66     bool leaf; //is terminal ?
     67     char v; //witch character this node represent ?
     68     node()
     69     { memset(s,0,sizeof(s)); f=p=NULL; leaf=false; }
     70 }pool[105000];
     71 node*pt=pool;
     72 
     73 node*qc[105000];
     74 node*qf[105000];
     75 int qh,qt;
     76 
     77 struct Trie
     78 {
     79     node*root;
     80     Trie(){ root=pt++; root->v='*'-'a'; }
     81     
     82     void Insert(char*f,int len)
     83     {
     84         node*x=root;
     85         for(int i=0;i<len;i++)
     86         {
     87             int v=f[i]-'a';
     88             if(x->s[v]==NULL)
     89             {
     90                 x->s[v]=pt++;
     91                 x->s[v]->p=x;
     92                 x->s[v]->v=v;
     93             }
     94             x=x->s[v];
     95         }
     96         x->leaf=true;
     97     }
     98     
     99     void Construct()
    100     {
    101         node*x=root;
    102         qh=qt=0;
    103         for(int i=0;i<26;i++)
    104         if(x->s[i]!=NULL)
    105         {
    106             x->s[i]->f=root;
    107             for(int j=0;j<26;j++)
    108             if(x->s[i]->s[j]!=NULL)
    109                 qc[qt]=x->s[i]->s[j],qf[qt]=root,qt++;
    110         }
    111         
    112         while(qh!=qt)
    113         {
    114             node*cur=qc[qh];
    115             node*fp=qf[qh];
    116             
    117             while(fp!=root && fp->s[cur->v]==NULL) fp=fp->f;
    118             if(fp->s[cur->v]!=NULL) fp=fp->s[cur->v];
    119             cur->f=fp;
    120             
    121             for(int i=0;i<26;i++)
    122                 if(cur->s[i]!=NULL)
    123                     qc[qt]=cur->s[i],qf[qt]=fp,qt++;
    124             
    125             qh++;
    126         }
    127     }
    128     
    129     node*GetTrans(node*x,int v)
    130     {
    131         if(x->s[v]!=NULL)
    132             return x->trans[v]=x->s[v];
    133         
    134         if(x->trans[v]==NULL)
    135         {
    136             if(x==root) return root;
    137             
    138             return x->trans[v]=GetTrans(x->f,v);
    139         }
    140         
    141         return x->trans[v];
    142     }
    143 
    144     
    145     
    146     void output() { output(root); }
    147     void output(node*x)
    148     {
    149         printf("%c %02d %p %p %p 
    ",x->v+'a',x->v,x,x->f,x->p);
    150         for(int i=0;i<26;i++)
    151         if(x->s[i]!=NULL) output(x->s[i]);
    152     }
    153 }T;
    154 
    155 node*_step[105000];
    156 node**step=_step+1;
    157 int _prev[105000];
    158 int*prev=_prev+1;
    159 
    160 int main()
    161 {
    162     freopen("censor.in","r",stdin);
    163     freopen("censor.out","w",stdout);
    164     
    165     scanf("%s",S);
    166     n=strlen(S);
    167     m=getint();
    168     for(int i=0;i<m;i++)
    169     {
    170         scanf("%s",inp);
    171         T.Insert(inp,strlen(inp));
    172     }
    173     
    174     T.Construct();
    175     
    176     step[-1]=T.root;
    177     prev[-1]=-1;
    178     for(int i=0;i<n;i++)
    179     prev[i]=i-1;
    180     
    181     for(int i=0;i<n;i++)
    182     {
    183         step[i]=T.GetTrans(step[i-1],S[i]-'a');
    184 
    185         if(step[i]->leaf) //we found a word.
    186         {
    187             node*p=step[i];
    188             int cur=i;
    189             while(p!=T.root && cur!=-1)
    190             {
    191                 S[cur]=0;
    192                 p=p->p;
    193                 cur=prev[cur];
    194             }
    195             
    196             step[i]=step[cur];
    197             prev[i+1]=cur;
    198         }
    199     }
    200     
    201     for(int i=0;i<n;i++)
    202     if(S[i]!=0)
    203     printf("%c",S[i]);
    204     printf("
    ");
    205     
    206     
    207     return 0;
    208 }
    View Code

    具体的,我们维护每个字符在自动机上的到达状态,然后匹配完毕后暴力删掉(用后向链表)匹配完毕的字符串,把当前状态变为删除字符串的前面一个字符的状态再接着匹配......

    注意由于有指针跳跃操作,AC自动机的f转移就不能均摊O(n)了,于是要预处理trans表示转移到哪个节点(而不是沿着f跑).....

    这里用了记忆化搜索呃.......

     


     

     

    另一个模板.

    AC BZOJ 1030

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42  
     43 db eps=1e-20;
     44 inline bool feq(db a,db b)
     45 { return fabs(a-b)<eps; }
     46 
     47 template<typename Type>
     48 inline Type avg(const Type a,const Type b)
     49 { return a+((b-a)/2); }
     50 
     51 //==========================================================
     52 //==========================================================
     53 //==========================================================
     54 //==========================================================
     55 
     56 const int MOD=(10007);
     57 
     58 inline void add(int&a,int&b)
     59 { a=(a+b)%MOD; }
     60 
     61 
     62 struct node
     63 {
     64     char v;
     65     node*s[26];
     66     node*trans[26];    
     67     node*f;
     68     bool danger;
     69     int code;
     70     node()
     71     {
     72         memset(s,0,sizeof(s));
     73         memset(trans,0,sizeof(trans));
     74         f=NULL;
     75         danger=false;
     76     }
     77 }pool[6050];
     78 node*nt=pool;
     79 
     80 node*newnode(char v)
     81 { nt->v=v; nt->code=int(nt-pool); return nt++; }
     82 
     83 struct trie
     84 {
     85     node*root;
     86     trie(){ root=newnode('*'-'A'); }
     87     
     88     void Insert(char *f,int len)
     89     {
     90         node*cur=root;
     91         for(int i=0;i<len;i++)
     92         {
     93             int v=f[i]-'A';
     94             if(cur->s[v]==NULL)
     95                 cur->s[v]=newnode(v);
     96             cur=cur->s[v];
     97         }
     98         cur->danger=true;
     99     }
    100     
    101     void construct() 
    102     {
    103         queue<node*> q;
    104         queue<node*> h;
    105         
    106         for(int i=0;i<26;i++)
    107         if(root->s[i])
    108         {
    109             root->s[i]->f=root;
    110             
    111             for(int j=0;j<26;j++)
    112             if(root->s[i]->s[j])
    113             q.push(root->s[i]->s[j]),h.push(root);
    114         }
    115         
    116         while(!q.empty())
    117         {
    118             node*x=q.front(); q.pop();
    119             node*p=h.front(); h.pop();
    120             
    121             //deal with current node.
    122             while(p!=root && !p->s[x->v]) p=p->f;
    123             if(p->s[x->v]) p=p->s[x->v];
    124             x->f=p;
    125             
    126             if(p->danger) x->danger=true;
    127             
    128             //expend sub trees.
    129             for(int i=0;i<26;i++)
    130             if(x->s[i]) q.push(x->s[i]),h.push(p);
    131         }
    132     }
    133     
    134     node* GetTrans(node*x,int v)
    135     {
    136         if(x->trans[v]) return x->trans[v];
    137         else return x->trans[v]=
    138         ( x->s[v] ? x->s[v] : ( x==root ? root : GetTrans(x->f,v) ) );
    139     }
    140 };
    141 
    142 int n,m;
    143 char inp[200];
    144 
    145 trie T;
    146 
    147 int d[105][6050];
    148 
    149 int main()
    150 {
    151     n=getint();
    152     m=getint();
    153     
    154     for(int i=0;i<n;i++)
    155     {
    156         scanf("%s",inp);
    157         T.Insert(inp,strlen(inp));
    158     }
    159     
    160     T.construct();
    161     
    162     d[0][0]=1;
    163     for(int h=1;h<=m;h++)
    164     {
    165         for(node*x=pool;x<nt;x++)
    166         {
    167             if(x->danger) continue;
    168             for(int i=0;i<26;i++)
    169                 add(d[h][T.GetTrans(x,i)->code],d[h-1][x->code]);
    170         }
    171     }
    172     
    173     int res=0;
    174     for(node*x=pool;x<nt;x++)
    175     if(!x->danger) add(res,d[m][x->code]);
    176     
    177     int de=1;
    178     for(int i=0;i<m;i++) 
    179     de=(de*26)%MOD;
    180     
    181     printf("%d
    ",((de-res)%MOD+MOD)%MOD);
    182     
    183     return 0;
    184 }
    View Code

    注意 if(p->danger) x->danger=true;这一句,用于判断某字符串是否为另一个字符串的后缀.

    不加这个的话,会错掉这个数据"2 2 ABA B",正确输出51.

     注意这个题的模式串很小,那个求trans的操作实际上是 $O(n^2)$ 的.

     


     

     

    AC BZOJ 3942 USACO Feb. Silver T1 Censoring

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42  
     43 db eps=1e-20;
     44 inline bool feq(db a,db b)
     45 { return fabs(a-b)<eps; }
     46 
     47 template<typename Type>
     48 inline Type avg(const Type a,const Type b)
     49 { return a+((b-a)/2); }
     50 
     51 //==============================================================================
     52 //==============================================================================
     53 //==============================================================================
     54 //==============================================================================
     55 
     56 char a[1005000];
     57 char s[1005000];
     58 int f[1005000];
     59 int tran[1005000][26];
     60 int _pre[1005000];
     61 int*pre=_pre+1;
     62 int _state[1005000];
     63 int*state=_state+1;
     64 
     65 inline int ch(char c) { return c-'a'; }
     66 inline char revh(int k) { return (char)(k+'a'); }
     67 
     68 char res[1005000];
     69 
     70 int n,m;
     71 
     72 int main()
     73 {
     74     scanf("%s%s",s,a);
     75     n=strlen(a);
     76     m=strlen(s);
     77     
     78     int p=-1;
     79     f[0]=p;
     80     for(int i=1;i<n;i++)
     81     {
     82         while(p!=-1 && a[p+1]!=a[i]) p=f[p];
     83         if(a[p+1]==a[i]) p++;
     84         f[i]=p;
     85     }
     86     
     87     for(int i=0;i<n;i++)
     88     for(int j=0;j<26;j++)
     89     {
     90         char c=revh(j);
     91         
     92         /*
     93         int p=i;
     94         while(p!=-1 && a[p+1]!=c) p=f[p];
     95         if(a[p+1]==c) p++;
     96         tran[i][j]=p;
     97         */
     98         
     99         if(a[i+1]==c) tran[i][j]=i+1;
    100         else tran[i][j]=( f[i]==-1 ? ( a[0]==c ? 0 : -1 ) : tran[f[i]][j] );
    101     }
    102     
    103     for(int i=0;i<m;i++) pre[i]=i-1;
    104     state[-1]=-1;
    105     int curp=-1;
    106     for(int i=0;i<m;i++)
    107     {
    108         char c=s[i];
    109         
    110         if(curp!=-1)
    111         curp=tran[curp][ch(c)];
    112         else 
    113         curp=( a[0]==c )-1;
    114         
    115         state[i]=curp;
    116         
    117         if(curp==n-1)
    118         {
    119             int p=i;
    120             for(int j=0;j<n;j++)
    121             {
    122                 s[p]=0;
    123                 p=pre[p];
    124             }
    125             curp=state[p];
    126             pre[i+1]=p;
    127         }
    128     }
    129     
    130     for(int i=0;i<m;i++) if(s[i]) printf("%c",s[i]); printf("
    ");
    131     
    132     return 0;
    133 }
    View Code

    拿了VJ上A掉的一道题去交结果TLE.......然后发现trans数组的递推的复杂度不对........

    由于数据规模极高,要改trans.....WA了两发.......

    递推求trans数组的时候注意对自动机的起点(编号-1)的处理.......

     

     


    AC BZOJ 2434 NOI2011 阿狸的打字机

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42 
     43 //==============================================================================
     44 //==============================================================================
     45 //==============================================================================
     46 //==============================================================================
     47 
     48 
     49 int s[105000][26];
     50 int pre[105000];
     51 int f[105000];
     52 int val[105000];
     53 int ncnt=2;
     54 
     55 int root=1;
     56 
     57 char a[105000];
     58 int p[105000],pcnt;
     59 
     60 int n,m;
     61 
     62 void BuildTrie()
     63 {
     64     int x=1;
     65     for(int i=0;i<n;i++)
     66     if(islower(a[i]))
     67     {
     68         int v=a[i]-'a';
     69         if(!s[x][v])
     70         {
     71             s[x][v]=ncnt;
     72             pre[ncnt]=x;
     73             val[ncnt]=v;
     74             ncnt++;
     75         }
     76         x=s[x][v];
     77     }
     78     else if(a[i]=='P')
     79         p[++pcnt]=x;
     80     else if(a[i]=='B')
     81         x=pre[x];
     82 }
     83 
     84 typedef pair<int,int> pl;
     85 queue<pl> q;
     86 void BuildAutomaton()
     87 {
     88     for(int i=0;i<26;i++)
     89     if(s[1][i])
     90     {
     91         f[s[1][i]]=1;
     92         for(int j=0;j<26;j++)
     93         if(s[s[1][i]][j])
     94         q.push(pl(s[s[1][i]][j],1));
     95     }
     96     
     97     while(!q.empty())
     98     {
     99         int x=q.front().first;
    100         int p=q.front().second;
    101         q.pop();
    102         int v=val[x];
    103         
    104         while(p!=1 && !s[p][v]) p=f[p];
    105         if(s[p][v]) p=s[p][v];
    106         f[x]=p;
    107         
    108         for(int i=0;i<26;i++)
    109         if(s[x][i]) q.push(pl(s[x][i],p));
    110     }
    111     
    112 }
    113 
    114 struct query_link
    115 {
    116     int x;
    117     int t;
    118     int res;
    119     query_link*nxt;
    120 
    121 }qpool[105000];
    122 query_link*qds[105000];
    123 bool cmp(const query_link&a,const query_link&b)
    124 { return a.t<b.t; }
    125 
    126 struct edge
    127 {
    128     int in;
    129     edge*nxt;
    130 }pool[105000];
    131 edge*et=pool;
    132 edge*eds[105000];
    133 void addedge(int a,int b)
    134 { et->in=b; et->nxt=eds[a]; eds[a]=et++; }
    135 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
    136 
    137 int loc[105000]; //points' location record.
    138 int lci[105000]; //location's points record.
    139 int tot[105000];
    140 int lcnt=0;
    141 
    142 int SeqBuildDFS(int x)
    143 {
    144     lci[lcnt++]=x;
    145     FOREACH_EDGE(e,x)
    146     tot[x]+=SeqBuildDFS(e->in);
    147     return tot[x]+=1;
    148 }
    149 
    150 int t[105000];
    151 void Change(int p,int v)
    152 { p++; for(;p<=lcnt;p+=(p&-p)) t[p]+=v; }
    153 int Query(int p)
    154 { p++; int res=0; for(;p;p-=(p&-p)) res+=t[p]; return res; }
    155 
    156 void DFS(int x)
    157 {
    158     if(x!=1) Change(loc[x],1);
    159     
    160     for(query_link*q=qds[x];q;q=q->nxt)
    161     q->res=Query(loc[q->x]+tot[q->x]-1)-Query(loc[q->x]-1);
    162     
    163     for(int i=0;i<26;i++)
    164     if(s[x][i]) DFS(s[x][i]);
    165     
    166     if(x!=1) Change(loc[x],-1);
    167 }
    168 
    169 
    170 int main()
    171 {
    172     scanf("%s",&a);
    173     n=strlen(a);
    174     
    175     BuildTrie();
    176     BuildAutomaton();
    177     
    178     for(int i=2;i<ncnt;i++)
    179     addedge(f[i],i);
    180     
    181     SeqBuildDFS(1);
    182     
    183     for(int i=0;i<lcnt;i++)
    184     loc[lci[i]]=i;
    185     
    186     m=getint();
    187     for(int i=0;i<m;i++)
    188     {
    189         int x=p[getint()];
    190         int y=p[getint()];
    191         qpool[i].x=x;
    192         qpool[i].t=i;
    193         qpool[i].nxt=qds[y];
    194         qds[y]=&qpool[i];
    195     }
    196     
    197     DFS(1);
    198     
    199     sort(qpool,qpool+m,cmp);
    200     for(int i=0;i<m;i++) printf("%d
    ",qpool[i].res);
    201     
    202     return 0;
    203 }
    View Code

     DFS写的AC自动机TLE了,不造是自己写搓还是复杂度本来就不对..........

    在AC自动机的Fail树上各种乱搞.........

    要求一个字符串x的对另外一个字符串y的匹配个数.

    考虑暴力,就是枚举y的前缀节点,如果一个前缀节点能跳跃到x的节点就把统计量+1.

    建出Fail树以后....就是神奇的乱搞.....真的好神奇.....

    我们想快速求出,对于每一个询问(x,y),在fail树上,y有多少个节点在x的子树下边.

    我们把Trie树DFS一遍,维护当前路径上的所有点(DFS栈中的点)的存在信息.

    具体来说,就是把Fail树的DFS序搞出来,每遍历到Trie树上一个节点就把这个节点在DFS序上的代表位置的值+1,离开就-1.这样区间查询一下就能很快求出某一个子树下有多少当前正在DFS栈中的点.....

    头一次写DFS序.....DFS序要注意两点,一是代表区间的长度等于子树大小;

    二是子树的根一定最先遍历到,所以在它的代表区间的最左边.

     


    AC BZOJ 3172

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21 typedef long double ldb;
     22  
     23 using namespace std;
     24  
     25 inline int getint()
     26 {
     27     int res=0;
     28     char c=getchar();
     29     while(c<'0' || c>'9') c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42 
     43 //==============================================================================
     44 //==============================================================================
     45 //==============================================================================
     46 //==============================================================================
     47 
     48 
     49 int s[1005000][26];
     50 int v[1005000];
     51 int c[1005000];
     52 int f[1005000];
     53 int ncnt=1;
     54 int Insert(char*a,int len)
     55 {
     56     int x=0;
     57     for(int i=0;i<len;i++)
     58     {
     59         int k=a[i]-'a';
     60         if(!s[x][k]) s[x][k]=ncnt++;
     61         x=s[x][k]; c[x]=k; v[x]++;
     62     }
     63     return x;
     64 }
     65 
     66 int q[1005000],qh,qt;
     67 int qr[1005000];
     68 void Build()
     69 {
     70     for(int i=0;i<26;i++)
     71     if(s[0][i])
     72     {
     73         f[s[0][i]]=0;
     74         for(int j=0;j<26;j++)
     75         if(s[s[0][i]][j])
     76         { qr[qt]=0; q[qt]=s[s[0][i]][j]; qt++; }
     77     }
     78     
     79     while(qh!=qt)
     80     {
     81         int x=q[qh];
     82         int p=qr[qh]; qh++;
     83         
     84         while(p && !s[p][c[x]]) p=f[p];
     85         if(s[p][c[x]]) p=s[p][c[x]];
     86         f[x]=p;
     87         
     88         for(int i=0;i<26;i++)
     89         if(s[x][i]) { q[qt]=s[x][i]; qr[qt]=p; qt++; }
     90     }
     91     
     92     //reversed BFS sequence is topological sorted.
     93     for(int i=qt-1;i>=0;i--) v[f[q[i]]]+=v[q[i]];
     94 }
     95 
     96 char st[100000];
     97 void DFS(int x,int dep)
     98 {
     99     if(x) st[dep]=c[x]+'a'; st[dep+1]=0;
    100     printf("%d %s %d %c %d
    ",x,st,v[x],c[x]+'a',f[x]);
    101     for(int i=0;i<26;i++) if(s[x][i]) DFS(s[x][i],dep+1);
    102 }
    103 
    104 int n;
    105 char inp[1005000];
    106 int loc[1005000];
    107 int main()
    108 {
    109     n=getint();
    110     for(int i=0;i<n;i++)
    111     {
    112         scanf("%s",inp);
    113         loc[i]=Insert(inp,strlen(inp));
    114     }
    115     
    116     Build();
    117     
    118     for(int i=0;i<n;i++) printf("%d
    ",v[loc[i]]);
    119     
    120     return 0;
    121 }
    View Code

    我的AC自动机代码向来比人家长一倍,抄了一下别人的代码结果狂WA不止....改成原始版本后就A了.....

    这个题应该也可以用后缀数据结构做....

    注意拓扑序不需要用拓扑排序求出来,BFS序的逆序满足拓扑关系.

    ...

     

  • 相关阅读:
    2017.5.11下午学习内容
    windows消息和消息队列
    探索Win32系统之窗口类(转载)
    WinMain函数详解(转载)
    Ajax爬取实战头条街拍美图
    Ajax实战微博
    Ajax请求分析实战
    ubuntu 安装rails
    ubuntu Thunderbird 接收邮件显示乱码的问题排除
    ubuntu 开机挂载windows分区
  • 原文地址:https://www.cnblogs.com/DragoonKiller/p/4328458.html
Copyright © 2011-2022 走看看