zoukankan      html  css  js  c++  java
  • 专题训练之AC自动机

    推荐博客:http://www.cnblogs.com/kuangbin/p/3164106.html AC自动机小结

    https://blog.csdn.net/creatorx/article/details/71100840 AC自动机最详细的解释

    2006年国家集训队论文:Trie图的构建、活用与改进 王赟

    1.(HDOJ2222)http://acm.hdu.edu.cn/showproblem.php?pid=2222

    题意:求目标串中出现了几个模式串。

    分析:AC自动机模板题

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<iostream>
      4 #include<cstring>
      5 #include<queue>
      6 using namespace std;
      7 const int maxn=500010;
      8 
      9 struct Trie
     10 {
     11     int nxt[maxn][26],fail[maxn],end[maxn]; //nxt为字典树, fail相当于kmp中的nxt数组, end对单词结尾做标记 
     12     int root,L;  //L相当于字典树中的sz ,root为根节点(即;0) 
     13     int newnode() //初相当于始化一个字典树上的节点 
     14     {
     15         for ( int i=0;i<26;i++ ) nxt[L][i]=-1;
     16         end[L++]=0;
     17         return L-1;
     18     }
     19     void init()
     20     {
     21         L=0;
     22         root=newnode();
     23     }
     24     void insert(char buf[]) //大致于字典树插入过程相同 
     25     {
     26         int len=strlen(buf);
     27         int now=root;
     28         for ( int i=0;i<len;i++ )
     29         {
     30             int x=buf[i]-'a';
     31             if ( nxt[now][x]==-1 ) nxt[now][x]=newnode();
     32             now=nxt[now][x];
     33         }
     34         end[now]++; //在单词结尾处做标记 
     35     }
     36     void build()  //相当于kmp的操作 
     37     {
     38         queue<int>que;
     39         fail[root]=root; //根节点初始化为0(即其本身)
     40         for (int i=0;i<26;i++ )
     41         {
     42             if ( nxt[root][i]==-1 ) nxt[root][i]=root;
     43             else //Trie中已经构建的节点 
     44             {
     45                 int x=nxt[root][i];
     46                 fail[x]=root;
     47                 que.push(x);
     48             }
     49         }
     50         while ( !que.empty() )
     51         {
     52             int now=que.front();
     53             que.pop();
     54             for ( int i=0;i<26;i++ )
     55             {
     56                 if ( nxt[now][i]==-1 ) //无后继点 
     57                     nxt[now][i]=nxt[fail[now]][i];//类似于kmp中求nxt数组一样 
     58                 else //存在下一个节点 
     59                 {
     60                     int x=nxt[now][i];
     61                     fail[x]=nxt[fail[now]][i];//失配指针指向他父节点的失配指针的下一个相同字符处 
     62                     que.push(x);
     63                 }
     64             }
     65         }
     66     }
     67     int query(char buf[]) //相当于字典树中的访问操作 
     68     {
     69         int len=strlen(buf);
     70         int now=root;
     71         int res=0;
     72         for ( int i=0;i<len;i++ ) 
     73         //沿着整个文本串移动,每移动到一个字符(节点) 时,通过失配指针不断找寻模式串 ,重点为源头,找到一个就将其标记清除 
     74         {
     75             now=nxt[now][buf[i]-'a'];
     76             int tmp=now;
     77             while ( tmp!=root )
     78             {
     79                 res+=end[tmp];
     80                 end[tmp]=0;
     81                 tmp=fail[tmp];
     82             }
     83         }
     84         return res; //返回单词个数 
     85     }
     86     void debug()
     87     {
     88         for ( int i=0;i<L;i++ )
     89         {
     90             printf("%id=%3d,fail=%3d,end=%3d,chi=[",i,fail[i],end[i]);
     91             for ( int j=0;j<26;j++ ) printf("%2d",nxt[i][j]);
     92             printf("]
    ");
     93         }
     94     }
     95 };
     96 char buf[maxn*2];
     97 Trie ac;
     98 int main()
     99 {
    100     int T,n;
    101     scanf("%d",&T);
    102     while ( T-- )
    103     {
    104         scanf("%d",&n);
    105         ac.init();
    106         for ( int i=0;i<n;i++ )
    107         {
    108             scanf("%s",buf);
    109             ac.insert(buf);
    110         }
    111         ac.build();
    112         scanf("%s",buf);
    113         printf("%d
    ",ac.query(buf));
    114     }
    115     return 0;
    116 }
    AC自动机模板(含解释) 
      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<iostream>
      4 #include<cstring>
      5 #include<queue>
      6 using namespace std;
      7 const int maxn=500010;
      8 const int maxm=26;
      9 
     10 struct Trie
     11 {
     12     int nxt[maxn][maxm],fail[maxn],end[maxn]; 
     13     int root,L;   
     14     int newnode()  
     15     {
     16         for ( int i=0;i<maxm;i++ ) nxt[L][i]=-1;
     17         end[L++]=0;
     18         return L-1;
     19     }
     20     void init()
     21     {
     22         L=0;
     23         root=newnode();
     24         memset(end,0,sizeof(end));
     25     }
     26     void insert(char buf[]) 
     27     {
     28         int len=strlen(buf);
     29         int now=root;
     30         for ( int i=0;i<len;i++ )
     31         {
     32             int x=buf[i]-'a';
     33             if ( nxt[now][x]==-1 ) nxt[now][x]=newnode();
     34             now=nxt[now][x];
     35         }
     36         end[now]++; 
     37     }
     38     void build()   
     39     {
     40         queue<int>que;
     41         fail[root]=root; 
     42         for (int i=0;i<maxm;i++ )
     43         {
     44             if ( nxt[root][i]==-1 ) nxt[root][i]=root;
     45             else 
     46             {
     47                 int x=nxt[root][i];
     48                 fail[x]=root;
     49                 que.push(x);
     50             }
     51         }
     52         while ( !que.empty() )
     53         {
     54             int now=que.front();
     55             que.pop();
     56             for ( int i=0;i<maxm;i++ )
     57             {
     58                 if ( nxt[now][i]==-1 ) 
     59                     nxt[now][i]=nxt[fail[now]][i];
     60                 else 
     61                 {
     62                     int x=nxt[now][i];
     63                     fail[x]=nxt[fail[now]][i];
     64                     que.push(x);
     65                 }
     66             }
     67         }
     68     }
     69     int query(char buf[]) 
     70     {
     71         int len=strlen(buf);
     72         int now=root;
     73         int res=0;
     74         for ( int i=0;i<len;i++ ) 
     75         {
     76             int x=buf[i]-'a';
     77             now=nxt[now][x];
     78             int tmp=now;
     79             while ( tmp!=root )
     80             {
     81                 res+=end[tmp];
     82                 end[tmp]=0;
     83                 tmp=fail[tmp];
     84             }
     85         }
     86         return res; 
     87     }
     88     void debug()
     89     {
     90         for ( int i=0;i<L;i++ )
     91         {
     92             printf("%id=%3d,fail=%3d,end=%3d,chi=[",i,fail[i],end[i]);
     93             for ( int j=0;j<26;j++ ) printf("%2d",nxt[i][j]);
     94             printf("]
    ");
     95         }
     96     }
     97 };
     98 char buf[maxn*2];
     99 Trie ac;
    100 int main()
    101 {
    102     int T,n;
    103     scanf("%d",&T);
    104     while ( T-- )
    105     {
    106         scanf("%d",&n);
    107         ac.init();
    108         for ( int i=0;i<n;i++ )
    109         {
    110             scanf("%s",buf);
    111             ac.insert(buf);
    112         }
    113         ac.build();
    114         scanf("%s",buf);
    115         printf("%d
    ",ac.query(buf));
    116     }
    117     return 0;
    118 }
    HDOJ2222

    2.(HDOJ2896)http://acm.hdu.edu.cn/showproblem.php?pid=2896

    分析:只需要将原模板中的end[i]标记为是第几个模式串的id(本来记录的是数量),再另外设置一个bool型的vis数组,当tmp指针访问到某一单词的结尾时,将编号为该单词的id的数在vis数组中标为true。同时注意是所有的ascii而不是只有小写英文字母,nxt数组的第二维开128的大小

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<queue>
      5 using namespace std;
      6 const int maxn=500010;
      7 const int maxm=128;
      8 const int maxk=510;
      9 char buf[maxn*2];
     10 bool vis[maxk];
     11 
     12 struct Trie
     13 {
     14     int nxt[maxn][maxm],end[maxn],fail[maxn];
     15     int root,L;
     16     int newnode()
     17     {
     18         for ( int i=0;i<maxm;i++ ) nxt[L][i]=-1;
     19         end[L++]=0;
     20         return L-1; 
     21     }
     22     void init()
     23     {
     24         L=0;
     25         root=newnode();
     26         memset(end,0,sizeof(end));
     27     }
     28     void insert(char buf[],int id)
     29     {
     30         int len=strlen(buf);
     31         int now=root;
     32         for ( int i=0;i<len;i++ )
     33         {
     34             int x=buf[i];
     35             if ( nxt[now][x]==-1 ) nxt[now][x]=newnode();
     36             now=nxt[now][x];
     37         }
     38         end[now]=id;
     39     }
     40     void build()
     41     {
     42         queue<int>que;
     43         fail[root]=root;
     44         for ( int i=0;i<maxm;i++ )
     45         {
     46             if ( nxt[root][i]==-1 ) nxt[root][i]=root;
     47             else 
     48             {
     49                 int x=nxt[root][i];
     50                 fail[x]=root;
     51                 que.push(x);
     52             }
     53         }
     54         while ( !que.empty() )
     55         {
     56             int now=que.front();
     57             que.pop();
     58             for ( int i=0;i<maxm;i++ )
     59             {
     60                 if ( nxt[now][i]==-1 ) nxt[now][i]=nxt[fail[now]][i];
     61                 else
     62                 {
     63                     int x=nxt[now][i];
     64                     fail[x]=nxt[fail[now]][i];
     65                     que.push(x);
     66                 }
     67             }
     68         }
     69     }
     70     bool query(char buf[])
     71     {
     72         int len=strlen(buf);
     73         int now=root;
     74         bool flag=false;
     75         for ( int i=0;i<len;i++ )
     76         {
     77             int x=buf[i];
     78             now=nxt[now][x];
     79             int tmp=now;
     80             while ( tmp!=root )
     81             {
     82                 if ( end[tmp]!=0 ) {
     83                     vis[end[tmp]]=true;
     84                     flag=true;
     85                 }
     86                 tmp=fail[tmp];
     87              } 
     88         }
     89         return flag;
     90     }
     91 };
     92 Trie ac;
     93 int main()
     94 {
     95     int T,n,m,ans;
     96     while ( scanf("%d",&n)!=EOF )
     97     {
     98         ans=0;
     99         ac.init();
    100         for ( int i=1;i<=n;i++ )
    101         {
    102             scanf("%s",buf);
    103             ac.insert(buf,i);
    104         }
    105         ac.build();
    106         scanf("%d",&m);
    107         for ( int i=1;i<=m;i++ )
    108         {
    109             memset(vis,false,sizeof(vis));
    110             scanf("%s",buf);
    111             if ( ac.query(buf) ) {
    112                 printf("web %d:",i);
    113                 for ( int j=1;j<=n;j++ )
    114                 {
    115                     if ( vis[j] ) printf(" %d",j);
    116                 }
    117                 printf("
    ");
    118                 ans++;
    119             }
    120         }
    121         printf("total: %d
    ",ans);
    122     }
    123     return 0;
    124 }
    HDOJ2896

    3.(HDOJ3065)http://acm.hdu.edu.cn/showproblem.php?pid=3065

    分析:只需要将上一题的bool型改成int型数组输出即可

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<queue>
      5 using namespace std;
      6 const int maxn=500010;
      7 const int maxq=2000010;
      8 const int maxm=128;
      9 const int maxk=1010;
     10 char buf[maxq];
     11 int vis[maxk];
     12 char s[maxk][55];
     13 
     14 struct Trie
     15 {
     16     int nxt[maxn][maxm],end[maxn],fail[maxn];
     17     int root,L;
     18     int newnode()
     19     {
     20         for ( int i=0;i<maxm;i++ ) nxt[L][i]=-1;
     21         end[L++]=0;
     22         return L-1; 
     23     }
     24     void init()
     25     {
     26         L=0;
     27         root=newnode();
     28         memset(end,0,sizeof(end));
     29     }
     30     void insert(char buf[],int id)
     31     {
     32         int len=strlen(buf);
     33         int now=root;
     34         for ( int i=0;i<len;i++ )
     35         {
     36             int x=buf[i];
     37             if ( nxt[now][x]==-1 ) nxt[now][x]=newnode();
     38             now=nxt[now][x];
     39         }
     40         end[now]=id;
     41     }
     42     void build()
     43     {
     44         queue<int>que;
     45         fail[root]=root;
     46         for ( int i=0;i<maxm;i++ )
     47         {
     48             if ( nxt[root][i]==-1 ) nxt[root][i]=root;
     49             else 
     50             {
     51                 int x=nxt[root][i];
     52                 fail[x]=root;
     53                 que.push(x);
     54             }
     55         }
     56         while ( !que.empty() )
     57         {
     58             int now=que.front();
     59             que.pop();
     60             for ( int i=0;i<maxm;i++ )
     61             {
     62                 if ( nxt[now][i]==-1 ) nxt[now][i]=nxt[fail[now]][i];
     63                 else
     64                 {
     65                     int x=nxt[now][i];
     66                     fail[x]=nxt[fail[now]][i];
     67                     que.push(x);
     68                 }
     69             }
     70         }
     71     }
     72     void query(char buf[])
     73     {
     74         int len=strlen(buf);
     75         int now=root;
     76         for ( int i=0;i<len;i++ )
     77         {
     78             int x=buf[i];
     79             now=nxt[now][x];
     80             int tmp=now;
     81             while ( tmp!=root )
     82             {
     83                 if ( end[tmp]!=0 ) vis[end[tmp]]++;
     84                 tmp=fail[tmp];
     85              } 
     86         }
     87         return;
     88     }
     89 };
     90 Trie ac;
     91 int main()
     92 {
     93     int T,n,m;
     94     while ( scanf("%d",&n)!=EOF )
     95     {
     96         ac.init();
     97         for ( int i=1;i<=n;i++ )
     98         {
     99             scanf("%s",s[i]);
    100             ac.insert(s[i],i);
    101         }
    102         ac.build();
    103         scanf("%s",buf);
    104         memset(vis,0,sizeof(vis));
    105         ac.query(buf);
    106         for ( int i=1;i<=n;i++ )
    107         {
    108             if ( vis[i]!=0 ) printf("%s: %d
    ",s[i],vis[i]);
    109         }
    110     }
    111     return 0;
    112 }
    HDOJ3065

    4.(POJ2778)http://poj.org/problem?id=2778

    题意:给出n个患病的DNA序列,问序列长度为m的,且不包含患病的DNA序列有多少种。

    分析:AC自动机+乘法矩阵,https://blog.csdn.net/morgan_xww/article/details/7834801推荐此博客有较详细的解释

    大致过程:将end[maxn]数组改成bool型,若为true表示该点是危险点,为false为安全点(初始时全为false)( 显然根结点是安全结点。 一个非根结点是危险结点的充要条件是: 它的路径字符串本身就是一个不良单词 ,或 它的路径字符串的后缀对应的结点(即fail[i])是危险结点)。增加longlong型的mat[maxn][maxn]数组,mat[i][j]表示节点i走一步到节点j有多少方案,当i和j都为安全点时才被计算进mat数组中(即所有满足条件的答案/不含模式串)。增加res[maxn][maxn]为mat阶乘m次后的答案。最后的答案为res[0][i](i从[0,L))的求和

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<iostream>
      4 #include<cstring>
      5 #include<queue>
      6 using namespace std;
      7 typedef long long ll;
      8 const int maxn=1e3+10;
      9 const int maxm=4;
     10 const int mod=1e5;
     11 
     12 struct Trie
     13 {
     14     int nxt[maxn][maxm],fail[maxn];
     15     ll mat[maxn][maxn];
     16     bool end[maxn]; 
     17     int root,L;   
     18     int newnode()  
     19     {
     20         for ( int i=0;i<maxm;i++ ) nxt[L][i]=-1;
     21         end[L++]=0;
     22         return L-1;
     23     }
     24     void init()
     25     {
     26         L=0;
     27         root=newnode();
     28         memset(end,false,sizeof(end));
     29         memset(mat,0,sizeof(mat));
     30     }
     31     int getid(char c)
     32     {
     33         if ( c=='A' ) return 0;
     34         else if ( c=='C' ) return 1;
     35         else if ( c=='T' ) return 2;
     36         else if ( c=='G' ) return 3;
     37     }
     38     void insert(char buf[]) 
     39     {
     40         int len=strlen(buf);
     41         int now=root;
     42         for ( int i=0;i<len;i++ )
     43         {
     44             int x=getid(buf[i]);
     45             if ( nxt[now][x]==-1 ) nxt[now][x]=newnode();
     46             now=nxt[now][x];
     47         }
     48         end[now]=true; 
     49     }
     50     void build()   
     51     {
     52         queue<int>que;
     53         fail[root]=root; 
     54         for (int i=0;i<maxm;i++ )
     55         {
     56             if ( nxt[root][i]==-1 ) nxt[root][i]=root;
     57             else 
     58             {
     59                 int x=nxt[root][i];
     60                 fail[x]=root;
     61                 que.push(x);
     62             }
     63         }
     64         while ( !que.empty() )
     65         {
     66             int now=que.front();
     67             que.pop();
     68             if ( end[fail[now]] ) end[now]=true;
     69             for ( int i=0;i<maxm;i++ )
     70             {
     71                 if ( nxt[now][i]==-1 ) 
     72                     nxt[now][i]=nxt[fail[now]][i];
     73                 else 
     74                 {
     75                     int x=nxt[now][i];
     76                     fail[x]=nxt[fail[now]][i];
     77                     que.push(x);
     78                 }
     79             }
     80         }
     81     }
     82     void setmat()
     83     {
     84         for ( int i=0;i<L;i++ )
     85         {
     86             for ( int j=0;j<maxm;j++ )
     87             {
     88                 if ( !end[i] && !end[nxt[i][j]] ) mat[i][nxt[i][j]]++;
     89             }
     90         }
     91     }
     92     void debug()
     93     {
     94         for ( int i=0;i<L;i++ )
     95         {
     96             for ( int j=0;j<L;j++ ) printf("%d ",mat[i][j]);
     97             printf("
    ");
     98         }
     99     }
    100     ll res[maxn][maxn],tmp[maxn][maxn];
    101     void mul(ll a[][maxn],ll b[][maxn])
    102     {
    103         for ( int i=0;i<L;i++ )
    104         {
    105             for ( int j=0;j<L;j++ )
    106             {
    107                 tmp[i][j]=0;
    108                 for ( int k=0;k<L;k++ ) tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%mod;
    109             }
    110         }
    111         for ( int i=0;i<L;i++ )
    112         {
    113             for ( int j=0;j<L;j++ ) a[i][j]=tmp[i][j]%mod;
    114         }
    115     }
    116     void pow(ll k)
    117     {
    118         memset(res,0,sizeof(res));
    119         for ( int i=0;i<L;i++ ) res[i][i]=1;
    120         while ( k )
    121         {
    122             if ( k&1 ) mul(res,mat);
    123             mul(mat,mat);
    124             k/=2;
    125         }
    126     }
    127 };
    128 char buf[105];
    129 Trie ac;
    130 int main()
    131 {
    132     int T,n,m;
    133     ll ans;
    134     while ( scanf("%d%d",&n,&m)!=EOF )
    135     {
    136         ac.init();
    137         for ( int i=0;i<n;i++ )
    138         {
    139             scanf("%s",buf);
    140             ac.insert(buf);
    141         }
    142         ac.build();
    143         ac.setmat();
    144         ac.pow(m);
    145         ans=0;
    146         for ( int i=0;i<ac.L;i++ ) 
    147         {
    148             ans=(ans+ac.res[0][i])%mod;
    149         }
    150         printf("%lld
    ",ans);
    151     }
    152     return 0;
    153 }
    POJ2778

    5.(HDOJ2243)http://acm.hdu.edu.cn/showproblem.php?pid=2243

    分析:和上题类似,不过不同之处有两点:1.该题是至少包含一个模式串(上一题是一个都没有) 2.该题最后得到的长度<=n(上一题是刚好为n)

    分析:大致做法于上题相同,难点在于如何解决两个不同。对于第一个不同采用反面的想法(即算出所有答案减去不含模式串的答案就为当前的答案),对于第二个考虑通过矩阵构造的方法

    记初始的mat矩阵为A,若想求得A^1+A^2……+A^n则需要构造一个这样的矩阵。

    注意:将运算过程中的变量和矩阵的元素定义为unsigned long long,就能实现自动对2^64自动取mod(即不用特地去取模)。

    特别注意两个矩阵的构造方法(一个是求26^1到26^n的求和,另外一个是A^1到A^n的求和),关注几次幂和矩阵大小

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<iostream>
      4 #include<cstring>
      5 #include<queue>
      6 #include<cmath>
      7 using namespace std;
      8 typedef long long ll;
      9 typedef unsigned long long ull;
     10 const int maxn=1e3+10;
     11 const int maxm=26;
     12 //const ll mod=0x3f3f3f3f;
     13 
     14 struct Trie
     15 {
     16     int nxt[maxn][maxm],fail[maxn];
     17     ull mat[maxn][maxn],num[4][4];
     18     bool end[maxn]; 
     19     int root,L;   
     20     int newnode()  
     21     {
     22         for ( int i=0;i<maxm;i++ ) nxt[L][i]=-1;
     23         end[L++]=0;
     24         return L-1;
     25     }
     26     void init()
     27     {
     28         L=0;
     29         root=newnode();
     30         memset(end,false,sizeof(end));
     31         memset(mat,0,sizeof(mat));
     32     }
     33     int getid(char c)
     34     {
     35         return c-'a';
     36     }
     37     void insert(char buf[]) 
     38     {
     39         int len=strlen(buf);
     40         int now=root;
     41         for ( int i=0;i<len;i++ )
     42         {
     43             int x=getid(buf[i]);
     44             if ( nxt[now][x]==-1 ) nxt[now][x]=newnode();
     45             now=nxt[now][x];
     46         }
     47         end[now]=true; 
     48     }
     49     void build()   
     50     {
     51         queue<int>que;
     52         fail[root]=root; 
     53         for (int i=0;i<maxm;i++ )
     54         {
     55             if ( nxt[root][i]==-1 ) nxt[root][i]=root;
     56             else 
     57             {
     58                 int x=nxt[root][i];
     59                 fail[x]=root;
     60                 que.push(x);
     61             }
     62         }
     63         while ( !que.empty() )
     64         {
     65             int now=que.front();
     66             que.pop();
     67             if ( end[fail[now]] ) end[now]=true;
     68             for ( int i=0;i<maxm;i++ )
     69             {
     70                 if ( nxt[now][i]==-1 ) 
     71                     nxt[now][i]=nxt[fail[now]][i];
     72                 else 
     73                 {
     74                     int x=nxt[now][i];
     75                     fail[x]=nxt[fail[now]][i];
     76                     que.push(x);
     77                 }
     78             }
     79         }
     80     }
     81     void setmat()
     82     {
     83         for ( int i=0;i<L;i++ )
     84         {
     85             for ( int j=0;j<maxm;j++ )
     86             {
     87                 if ( !end[i] && !end[nxt[i][j]] ) mat[i][nxt[i][j]]++;
     88             }
     89         }
     90         for ( int i=0;i<=L;i++ ) mat[i][L]=1;
     91     }
     92     void debug()
     93     {
     94         for ( int i=0;i<L;i++ )
     95         {
     96             for ( int j=0;j<L;j++ ) printf("%d ",mat[i][j]);
     97             printf("
    ");
     98         }
     99     }
    100     ull res[maxn][maxn],tmp[maxn][maxn];
    101     void mul(ull a[][maxn],ull b[][maxn],ll l)
    102     {
    103         for ( int i=0;i<l;i++ )
    104         {
    105             for ( int j=0;j<l;j++ )
    106             {
    107                 tmp[i][j]=0;
    108                 for ( int k=0;k<l;k++ ) tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j]);
    109             }
    110         }
    111         for ( int i=0;i<l;i++ )
    112         {
    113             for ( int j=0;j<l;j++ ) a[i][j]=tmp[i][j];
    114         }
    115     }
    116     void pow(ll k,ll l)
    117     {
    118         memset(res,0,sizeof(res));
    119         for ( int i=0;i<l;i++ ) res[i][i]=1;
    120         while ( k )
    121         {
    122             if ( k&1 ) mul(res,mat,l);
    123             mul(mat,mat,l);
    124             k/=2;
    125         }
    126     }
    127 };
    128 char buf[10];
    129 Trie ac;
    130 int main()
    131 {
    132     int T,n,m;
    133     ull ans,sum;
    134     while ( scanf("%d%d",&n,&m)!=EOF )
    135     {
    136         ac.init();
    137         for ( int i=0;i<n;i++ )
    138         {
    139             scanf("%s",buf);
    140             ac.insert(buf);
    141         }
    142         ac.build();
    143         ac.setmat();
    144         //ac.debug();
    145         ac.pow(m,ac.L+1);
    146         ans=0;
    147         for ( int i=0;i<=ac.L;i++ ) 
    148         {
    149             ans=(ans+ac.res[0][i]);
    150         }
    151         ac.mat[0][0]=26;
    152         ac.mat[0][1]=ac.mat[1][1]=1;
    153         ac.mat[1][0]=0;
    154         ac.pow(m+1,2);
    155         sum=ac.res[0][1];
    156         ans=(sum-ans);
    157         printf("%I64u
    ",ans);
    158     }
    159     return 0;
    160 }
    HDOJ2243

    6.(HDOJ2457)http://acm.hdu.edu.cn/showproblem.php?pid=2457

    题意:给定N(N <= 50)个长度不超过20的模式串,再给定一个长度为M(M <= 1000)的目标串S,求在目标串S上最少改变多少字符,可以使得它不包含任何的模式串(所有串只有ACGT四种字符)

    分析:AC自动机+dp。先通过AC自动机得到Trie图,然后通过Trie图去构建字符串。设dp[i][j]表示长度为i,状态为j(这里的状态和节点的编号相对应)的字符串变成目标串前i位需要的最少操作次数。初始化:dp[0][0]=0(初始状态),其他一律设置为inf。具体转移及细节见代码

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<iostream>
      4 #include<cstring>
      5 #include<queue>
      6 using namespace std;
      7 const int maxn=1010;
      8 const int maxm=4;
      9 const int inf=1e9;
     10 int dp[maxn][maxn];
     11 
     12 struct Trie
     13 {
     14     int nxt[maxn][maxm],fail[maxn];
     15     bool end[maxn]; 
     16     int root,L;   
     17     int newnode()  
     18     {
     19         for ( int i=0;i<maxm;i++ ) nxt[L][i]=-1;
     20         end[L++]=0;
     21         return L-1;
     22     }
     23     void init()
     24     {
     25         L=0;
     26         root=newnode();
     27         memset(end,false,sizeof(end));
     28     }
     29     int getid(char c)
     30     {
     31         if ( c=='A' ) return 0;
     32         else if ( c=='T' ) return 1;
     33         else if ( c=='G' ) return 2;
     34         else if ( c=='C' ) return 3;
     35     }
     36     void insert(char buf[]) 
     37     {
     38         int len=strlen(buf);
     39         int now=root;
     40         for ( int i=0;i<len;i++ )
     41         {
     42             int x=getid(buf[i]);
     43             if ( nxt[now][x]==-1 ) nxt[now][x]=newnode();
     44             now=nxt[now][x];
     45         }
     46         end[now]=true; 
     47     }
     48     void build()   
     49     {
     50         queue<int>que;
     51         fail[root]=root; 
     52         for (int i=0;i<maxm;i++ )
     53         {
     54             if ( nxt[root][i]==-1 ) nxt[root][i]=root;
     55             else 
     56             {
     57                 int x=nxt[root][i];
     58                 fail[x]=root;
     59                 que.push(x);
     60             }
     61         }
     62         while ( !que.empty() )
     63         {
     64             int now=que.front();
     65             que.pop();
     66             if ( end[fail[now]] ) end[now]=true;
     67             for ( int i=0;i<maxm;i++ )
     68             {
     69                 if ( nxt[now][i]==-1 ) 
     70                     nxt[now][i]=nxt[fail[now]][i];
     71                 else 
     72                 {
     73                     int x=nxt[now][i];
     74                     fail[x]=nxt[fail[now]][i];
     75                     que.push(x);
     76                 }
     77             }
     78         }
     79     }
     80     int query(char buf[]) 
     81     {
     82         int len=strlen(buf);
     83         int now=root;
     84         int res=0;
     85         for ( int i=0;i<len;i++ ) 
     86         {
     87             int x=getid(buf[i]);
     88             now=nxt[now][x];
     89             int tmp=now;
     90             while ( tmp!=root )
     91             {
     92                 res+=end[tmp];
     93                 end[tmp]=0;
     94                 tmp=fail[tmp];
     95             }
     96         }
     97         return res; 
     98     }
     99 };
    100 char buf[maxn];
    101 Trie ac;
    102 int main()
    103 {
    104     int n,h=0;
    105     while ( scanf("%d",&n)!=EOF && n )
    106     {
    107         ac.init();
    108         for ( int i=0;i<n;i++ )
    109         {
    110             scanf("%s",buf);
    111             ac.insert(buf);
    112         }
    113         ac.build();
    114         scanf("%s",buf);
    115         int len=strlen(buf);
    116         for ( int i=0;i<=len;i++ )
    117             for ( int j=0;j<ac.L;j++ ) dp[i][j]=inf;
    118         dp[0][ac.root]=0;
    119         for ( int i=0;i<len;i++ )
    120             for ( int j=0;j<ac.L;j++ )
    121                 if ( dp[i][j]<inf ) 
    122                 {
    123                     for ( int k=0;k<maxm;k++ )
    124                     {
    125                         int news=ac.nxt[j][k];
    126                         if ( ac.end[news] ) continue;
    127                         int x=ac.getid(buf[i]);
    128                         int add;
    129                         if ( x==k ) add=0;
    130                         else add=1;
    131                         dp[i+1][news]=min(dp[i+1][news],add+dp[i][j]);
    132                     }
    133                 }
    134         int ans=inf;
    135         for ( int j=0;j<ac.L;j++ ) ans=min(ans,dp[len][j]);
    136         printf("Case %d: ",++h);
    137         if ( ans==inf ) printf("-1
    ");
    138         else printf("%d
    ",ans);
    139     }
    140     return 0;
    141 }
    HDOJ2457

    待做:1.(POJ1699)http://poj.org/problem?id=1699

    2.(HDOJ2296)http://acm.hdu.edu.cn/showproblem.php?pid=2296

    3.(HDOJ3341)http://acm.hdu.edu.cn/showproblem.php?pid=3341

    4.(HDOJ3247)http://acm.hdu.edu.cn/showproblem.php?pid=3247

    小结:AC自动机一般适用于多串匹配,往往是通过构造去求一些关于不含模式串的字符串类型的题目,构造过程往往在Trie图中按照一定要求(一般为是否该点/状态为安全点)进行,Trie图中的每一个点代表一个状态,从一个点有maxm(字符类型的总个数)个移动方向,危险点往往不参与构造(即只有安全点才参与)。

  • 相关阅读:
    C# lock
    read appSettings in configuration file by XElement with xmlns
    get all sites under IIS
    Cross-site scripting(XSS)
    Do not throw System.Exception, System.SystemException, System.NullReferenceException, or System.IndexOutOfRangeException intentionally from your own source code
    C++ 算法
    C++ 数据结构概念
    C++ STL 常用算术和生成算法
    C++ STL 常用拷贝和替换算法
    C++ STL 常用排序算法
  • 原文地址:https://www.cnblogs.com/HDUjackyan/p/9043255.html
Copyright © 2011-2022 走看看