转自kuangbin的AC自动机(赛前最后一博)

有了KMP和Trie的基础,就可以学习神奇的AC自动机了。AC自动机其实就是在Trie树上实现KMP,可以完成多模式串的匹配。

          AC自动机 其实 就是创建了一个状态的转移图,思想很重要。

          推荐的学习链接:

http://acm.uestc.edu.cn/bbs/read.php?tid=4294

http://blog.csdn.net/niushuai666/article/details/7002823

http://hi.baidu.com/nialv7/item/ce1ce015d44a6ba7feded52d

AC自动机专题训练链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=25605#overview     这里我提交的代码是公开的,可以看到

题目来源:http://www.notonlysuccess.com/index.php/aho-corasick-automaton/

写AC自动机的代码风格是向昀神学的,好简洁,写起来好棒的感觉。

1、HDU 2222 Keywords Search    最基本的入门题了

就是求目标串中出现了几个模式串。

很基础了。使用一个int型的end数组记录,查询一次。

//======================
// HDU 2222
// 求目标串中出现了几个模式串
//====================
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;

struct Trie
{
    int next[500010][26],fail[500010],end[500010];
    int root,L;
    int newnode()
    {
        for(int i = 0;i < 26;i++)
            next[L][i] = -1;
        end[L++] = 0;
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(char buf[])
    {
        int len = strlen(buf);
        int now = root;
        for(int i = 0;i < len;i++)
        {
            if(next[now][buf[i]-‘a‘] == -1)
                next[now][buf[i]-‘a‘] = newnode();
            now = next[now][buf[i]-‘a‘];
        }
        end[now]++;
    }
    void build()
    {
        queue<int>Q;
        fail[root] = root;
        for(int i = 0;i < 26;i++)
            if(next[root][i] == -1)
                next[root][i] = root;
            else
            {
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        while( !Q.empty() )
        {
            int now = Q.front();
            Q.pop();
            for(int i = 0;i < 26;i++)
                if(next[now][i] == -1)
                    next[now][i] = next[fail[now]][i];
                else
                {
                    fail[next[now][i]]=next[fail[now]][i];
                    Q.push(next[now][i]);
                }
        }
    }
    int query(char buf[])
    {
        int len = strlen(buf);
        int now = root;
        int res = 0;
        for(int i = 0;i < len;i++)
        {
            now = next[now][buf[i]-‘a‘];
            int temp = now;
            while( temp != root )
            {
                res += end[temp];
                end[temp] = 0;
                temp = fail[temp];
            }
        }
        return res;
    }
    void debug()
    {
        for(int i = 0;i < L;i++)
        {
            printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
            for(int j = 0;j < 26;j++)
                printf("%2d",next[i][j]);
            printf("]\n");
        }
    }
};
char buf[1000010];
Trie ac;
int main()
{
    int T;
    int n;
    scanf("%d",&T);
    while( T-- )
    {
        scanf("%d",&n);
        ac.init();
        for(int i = 0;i < n;i++)
        {
            scanf("%s",buf);
            ac.insert(buf);
        }
        ac.build();
        scanf("%s",buf);
        printf("%d\n",ac.query(buf));
    }
    return 0;
}

2、HDU 2896 病毒侵袭  

这题和上题差不多,要输出出现模式串的id,用end记录id就可以了。还有trie树的分支是128的

题解here

//============================================================================
// Name        : HDU.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

struct Trie
{
    int next[210*500][128],fail[210*500],end[210*500];
    int root,L;
    int newnode()
    {
        for(int i = 0;i < 128;i++)
            next[L][i] = -1;
        end[L++] = -1;
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(char s[],int id)
    {
        int len = strlen(s);
        int now = root;
        for(int i = 0;i < len;i++)
        {
            if(next[now][s[i]] == -1)
                next[now][s[i]] = newnode();
            now=next[now][s[i]];
        }
        end[now]=id;
    }
    void build()
    {
        queue<int>Q;
        fail[root] = root;
        for(int i = 0;i < 128;i++)
            if(next[root][i] == -1)
                next[root][i] = root;
            else
            {
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();
            for(int i = 0;i < 128;i++)
                if(next[now][i] == -1)
                    next[now][i] = next[fail[now]][i];
                else
                {
                    fail[next[now][i]] = next[fail[now]][i];
                    Q.push(next[now][i]);
                }
        }
    }
    bool used[510];
    bool query(char buf[],int n,int id)
    {
        int len = strlen(buf);
        int now = root;
        memset(used,false,sizeof(used));
        bool flag = false;
        for(int i = 0;i < len;i++)
        {
            now = next[now][buf[i]];
            int temp = now;
            while(temp != root)
            {
                if(end[temp] != -1)
                {
                    used[end[temp]] = true;
                    flag = true;
                }
                temp = fail[temp];
            }
        }
        if(!flag)return false;
        printf("web %d:",id);
        for(int i = 1;i <= n;i++)
            if(used[i])
                printf(" %d",i);
        printf("\n");
        return true;
    }
};
char buf[10010];
Trie ac;
int main()
{
    int n,m;
    while(scanf("%d",&n) != EOF)
    {
        ac.init();
        for(int i = 1;i <= n;i++)
        {
            scanf("%s",buf);
            ac.insert(buf,i);
        }
        ac.build();
        int ans = 0;
        scanf("%d",&m);
        for(int i = 1;i <= m;i++)
        {
            scanf("%s",buf);
            if(ac.query(buf,n,i))
                ans++;
        }
        printf("total: %d\n",ans);
    }
    return 0;
}

3、HDU 3065 病毒侵袭持续中

这题的变化也不大,就是需要输出每个模式串出现的次数,查询的时候使用一个数组进行记录就可以了

  1 //============================================================================
  2 // Name        : HDU.cpp
  3 // Author      :
  4 // Version     :
  5 // Copyright   : Your copyright notice
  6 // Description : Hello World in C++, Ansi-style
  7 //============================================================================
  8
  9 #include <iostream>
 10 #include <stdio.h>
 11 #include <string.h>
 12 #include <algorithm>
 13 #include <queue>
 14 using namespace std;
 15
 16 char str[1010][100];
 17 struct Trie
 18 {
 19     int next[1010*50][128],fail[1010*50],end[1010*50];
 20     int root,L;
 21     int newnode()
 22     {
 23         for(int i = 0;i < 128;i++)
 24             next[L][i] = -1;
 25         end[L++] = -1;
 26         return L-1;
 27     }
 28     void init()
 29     {
 30         L = 0;
 31         root = newnode();
 32     }
 33     void insert(char s[],int id)
 34     {
 35         int len = strlen(s);
 36         int now = root;
 37         for(int i = 0;i < len;i++)
 38         {
 39             if(next[now][s[i]] == -1)
 40                 next[now][s[i]] = newnode();
 41             now = next[now][s[i]];
 42         }
 43         end[now] = id;
 44     }
 45     void build()
 46     {
 47         queue<int>Q;
 48         fail[root] = root;
 49         for(int i = 0;i < 128;i++)
 50             if(next[root][i] == -1)
 51                 next[root][i] = root;
 52             else
 53             {
 54                 fail[next[root][i]] = root;
 55                 Q.push(next[root][i]);
 56             }
 57         while(!Q.empty())
 58         {
 59             int now = Q.front();
 60             Q.pop();
 61             for(int i = 0;i < 128;i++)
 62                 if(next[now][i] == -1)
 63                     next[now][i]=next[fail[now]][i];
 64                 else
 65                 {
 66                     fail[next[now][i]]=next[fail[now]][i];
 67                     Q.push(next[now][i]);
 68                 }
 69         }
 70     }
 71     int num[1010];
 72     void query(char buf[],int n)
 73     {
 74         for(int i = 0;i < n;i++)
 75             num[i] = 0;
 76         int len=strlen(buf);
 77         int now=root;
 78         for(int i=0;i<len;i++)
 79         {
 80             now=next[now][buf[i]];
 81             int temp = now;
 82             while( temp != root )
 83             {
 84                 if(end[temp] != -1)
 85                     num[end[temp]]++;
 86                 temp = fail[temp];
 87             }
 88         }
 89         for(int i = 0;i < n;i++)
 90             if(num[i] > 0)
 91                 printf("%s: %d\n",str[i],num[i]);
 92     }
 93
 94 };
 95
 96 char buf[2000010];
 97 Trie ac;
 98 void debug()
 99 {
100     for (int i = 0; i < ac.L; i++)
101     {
102         printf("id = %3d ,fail = %3d ,end = %3d, chi = [",i,ac.fail[i],ac.end[i]);
103         for (int j = 0; j < 128; j++)
104             printf("%2d ",ac.next[i][j]);
105         printf("]\n");
106     }
107 }
108 int main()
109 {
110 //    freopen("in.txt","r",stdin);
111 //    freopen("out.txt","w",stdout);
112     int n;
113     while(scanf("%d",&n) == 1)
114     {
115         ac.init();
116         for(int i = 0;i < n;i++)
117         {
118             scanf("%s",str[i]);
119             ac.insert(str[i],i);
120         }
121         ac.build();
122         scanf("%s",buf);
123         ac.query(buf,n);
124     }
125     return 0;
126 }

4、ZOJ 3430 Detect the Virus

主要是解码过程,解码以后就是模板题了。

求出现的模式串的种类数

分支需要256个

  1 //============================================================================
  2 // Name        : ZOJ.cpp
  3 // Author      :
  4 // Version     :
  5 // Copyright   : Your copyright notice
  6 // Description : Hello World in C++, Ansi-style
  7 //============================================================================
  8
  9 #include <iostream>
 10 #include <stdio.h>
 11 #include <string.h>
 12 #include <algorithm>
 13 #include <queue>
 14 using namespace std;
 15
 16 struct Trie
 17 {
 18     int next[520*64][256],fail[520*64],end[520*64];
 19     int root,L;
 20     int newnode()
 21     {
 22         for(int i = 0;i < 256;i++)
 23             next[L][i] = -1;
 24         end[L++] = -1;
 25         return L-1;
 26     }
 27     void init()
 28     {
 29         L = 0;
 30         root = newnode();
 31     }
 32     void insert(unsigned char buf[],int len,int id)
 33     {
 34         int now = root;
 35         for(int i = 0;i < len;i++)
 36         {
 37             if(next[now][buf[i]] == -1)
 38                 next[now][buf[i]] = newnode();
 39             now = next[now][buf[i]];
 40         }
 41         end[now] = id;
 42     }
 43     void build()
 44     {
 45         queue<int>Q;
 46         fail[root] = root;
 47         for(int i = 0;i < 256;i++)
 48             if(next[root][i] == -1)
 49                 next[root][i] = root;
 50             else
 51             {
 52                 fail[next[root][i]]=root;
 53                 Q.push(next[root][i]);
 54             }
 55         while(!Q.empty())
 56         {
 57             int now = Q.front();
 58             Q.pop();
 59             for(int i = 0;i < 256;i++)
 60                 if(next[now][i] == -1)
 61                     next[now][i] = next[fail[now]][i];
 62                 else
 63                 {
 64                     fail[next[now][i]] = next[fail[now]][i];
 65                     Q.push(next[now][i]);
 66                 }
 67         }
 68     }
 69     bool used[520];
 70     int query(unsigned char buf[],int len,int n)
 71     {
 72         memset(used,false,sizeof(used));
 73         int now = root;
 74         for(int i = 0;i < len;i++)
 75         {
 76             now = next[now][buf[i]];
 77             int temp = now;
 78             while( temp!=root )
 79             {
 80                 if(end[temp] != -1)
 81                     used[end[temp]]=true;
 82                 temp = fail[temp];
 83             }
 84         }
 85         int res = 0;
 86         for(int i = 0;i < n;i++)
 87             if(used[i])
 88                 res++;
 89         return res;
 90     }
 91 };
 92
 93 unsigned char buf[2050];
 94 int tot;
 95 char str[4000];
 96 unsigned char s[4000];
 97 unsigned char Get(char ch)
 98 {
 99     if( ch>=‘A‘&&ch<=‘Z‘ )return ch-‘A‘;
100     if( ch>=‘a‘&&ch<=‘z‘ )return ch-‘a‘+26;
101     if( ch>=‘0‘&&ch<=‘9‘ )return ch-‘0‘+52;
102     if( ch==‘+‘ )return 62;
103     else return 63;
104 }
105 void change(unsigned char str[],int len)
106 {
107     int t=0;
108     for(int i=0;i<len;i+=4)
109     {
110         buf[t++]=((str[i]<<2)|(str[i+1]>>4));
111         if(i+2 < len)
112             buf[t++]=( (str[i+1]<<4)|(str[i+2]>>2) );
113         if(i+3 < len)
114             buf[t++]= ( (str[i+2]<<6)|str[i+3] );
115     }
116     tot=t;
117 }
118 Trie ac;
119 int main()
120 {
121 //    freopen("in.txt","r",stdin);
122 //    freopen("out.txt","w",stdout);
123     int n,m;
124     while(scanf("%d",&n) == 1)
125     {
126         ac.init();
127         for(int i = 0;i < n;i++)
128         {
129             scanf("%s",str);
130             int len = strlen(str);
131             while(str[len-1]==‘=‘)len--;
132             for(int j = 0;j < len;j++)
133             {
134                 s[j] = Get(str[j]);
135             }
136             change(s,len);
137             ac.insert(buf,tot,i);
138         }
139         ac.build();
140         scanf("%d",&m);
141         while(m--)
142         {
143             scanf("%s",str);
144             int len=strlen(str);
145             while(str[len-1]==‘=‘)len--;
146             for(int j = 0;j < len;j++)
147                 s[j] = Get(str[j]);
148             change(s,len);
149             printf("%d\n",ac.query(buf,tot,n));
150         }
151         printf("\n");
152     }
153     return 0;
154 }

5、POJ 2778 DNA Sequence

AC自动机+矩阵加速

这个时候AC自动机 的一种状态转移图的思路就很透彻了。

AC自动机就是可以确定状态的转移。

  1 //============================================================================
  2 // Name        : POJ.cpp
  3 // Author      :
  4 // Version     :
  5 // Copyright   : Your copyright notice
  6 // Description : Hello World in C++, Ansi-style
  7 //============================================================================
  8
  9 #include <iostream>
 10 #include <stdio.h>
 11 #include <algorithm>
 12 #include <string.h>
 13 #include <queue>
 14 using namespace std;
 15
 16 const int MOD=100000;
 17 struct Matrix
 18 {
 19     int mat[110][110],n;
 20     Matrix(){}
 21     Matrix(int _n)
 22     {
 23         n = _n;
 24         for(int i=0;i<n;i++)
 25             for(int j=0;j<n;j++)
 26                 mat[i][j]=0;
 27     }
 28     Matrix operator *(const Matrix &b)const
 29     {
 30         Matrix ret=Matrix(n);
 31         for(int i=0;i<n;i++)
 32             for(int j=0;j<n;j++)
 33                 for(int k=0;k<n;k++)
 34                 {
 35                     int tmp=(long long)mat[i][k]*b.mat[k][j]%MOD;
 36                     ret.mat[i][j]=(ret.mat[i][j]+tmp)%MOD;
 37                 }
 38         return ret;
 39     }
 40 };
 41 struct Trie
 42 {
 43     int next[110][4],fail[110];
 44     bool end[110];
 45     int root,L;
 46     int newnode()
 47     {
 48         for(int i=0;i<4;i++)
 49             next[L][i]=-1;
 50         end[L++]=false;
 51         return L-1;
 52     }
 53     void init()
 54     {
 55         L=0;
 56         root=newnode();
 57     }
 58     int getch(char ch)
 59     {
 60         switch(ch)
 61         {
 62         case ‘A‘:
 63             return 0;
 64             break;
 65         case ‘C‘:
 66             return 1;
 67             break;
 68         case ‘G‘:
 69             return 2;
 70             break;
 71         case ‘T‘:
 72             return 3;
 73             break;
 74         }
 75     }
 76     void insert(char s[])
 77     {
 78         int len=strlen(s);
 79         int now=root;
 80         for(int i = 0;i < len;i++)
 81         {
 82             if(next[now][getch(s[i])] == -1)
 83                 next[now][getch(s[i])] = newnode();
 84             now = next[now][getch(s[i])];
 85         }
 86         end[now]=true;
 87     }
 88     void build()
 89     {
 90         queue<int>Q;
 91         for(int i = 0;i < 4;i++)
 92             if(next[root][i] == -1)
 93                 next[root][i] = root;
 94             else
 95             {
 96                 fail[next[root][i]] = root;
 97                 Q.push(next[root][i]);
 98             }
 99         while(!Q.empty())
100         {
101             int now = Q.front();
102             Q.pop();
103             if(end[fail[now]]==true)
104                 end[now]=true;
105             for(int i = 0;i < 4;i++)
106             {
107                 if(next[now][i] == -1)
108                     next[now][i] = next[fail[now]][i];
109                 else
110                 {
111                     fail[next[now][i]] = next[fail[now]][i];
112                     Q.push(next[now][i]);
113                 }
114             }
115         }
116     }
117     Matrix getMatrix()
118     {
119         Matrix res = Matrix(L);
120         for(int i=0;i<L;i++)
121             for(int j=0;j<4;j++)
122                 if(end[next[i][j]]==false)
123                     res.mat[i][next[i][j]]++;
124         return res;
125     }
126 };
127
128 Trie ac;
129 char buf[20];
130
131 Matrix pow_M(Matrix a,int n)
132 {
133     Matrix ret = Matrix(a.n);
134     for(int i = 0; i < ret.n; i++)
135         ret.mat[i][i]=1;
136     Matrix tmp=a;
137     while(n)
138     {
139         if(n&1)ret=ret*tmp;
140         tmp=tmp*tmp;
141         n>>=1;
142     }
143     return ret;
144 }
145
146 int main()
147 {
148     int n,m;
149     while(scanf("%d%d",&n,&m) != EOF)
150     {
151         ac.init();
152         for(int i=0;i<n;i++)
153         {
154             scanf("%s",buf);
155             ac.insert(buf);
156         }
157         ac.build();
158         Matrix a=ac.getMatrix();
159         a=pow_M(a,m);
160         int ans=0;
161         for(int i=0;i<a.n;i++)
162         {
163             ans=(ans+a.mat[0][i])%MOD;
164         }
165         printf("%d\n",ans);
166     }
167     return 0;
168 }

6、HDU 2243 考研路茫茫——单词情结

这题和上题有些类似。但是需要求和。

所以给

矩阵增加一维,这样可以完美解决

题解here

  1 //============================================================================
  2 // Name        : HDU.cpp
  3 // Author      :
  4 // Version     :
  5 // Copyright   : Your copyright notice
  6 // Description : Hello World in C++, Ansi-style
  7 //============================================================================
  8
  9 #include <iostream>
 10 #include <stdio.h>
 11 #include <string.h>
 12 #include <algorithm>
 13 #include <queue>
 14 using namespace std;
 15 struct Matrix
 16 {
 17     unsigned long long mat[40][40];
 18     int n;
 19     Matrix(){}
 20     Matrix(int _n)
 21     {
 22         n=_n;
 23         for(int i=0;i<n;i++)
 24             for(int j=0;j<n;j++)
 25                 mat[i][j] = 0;
 26     }
 27     Matrix operator *(const Matrix &b)const
 28     {
 29         Matrix ret = Matrix(n);
 30         for(int i=0;i<n;i++)
 31             for(int j=0;j<n;j++)
 32                 for(int k=0;k<n;k++)
 33                     ret.mat[i][j]+=mat[i][k]*b.mat[k][j];
 34         return ret;
 35     }
 36 };
 37 unsigned long long pow_m(unsigned long long a,int n)
 38 {
 39     unsigned long long ret=1;
 40     unsigned long long tmp = a;
 41     while(n)
 42     {
 43         if(n&1)ret*=tmp;
 44         tmp*=tmp;
 45         n>>=1;
 46     }
 47     return ret;
 48 }
 49 Matrix pow_M(Matrix a,int n)
 50 {
 51     Matrix ret = Matrix(a.n);
 52     for(int i=0;i<a.n;i++)
 53         ret.mat[i][i] = 1;
 54     Matrix tmp = a;
 55     while(n)
 56     {
 57         if(n&1)ret=ret*tmp;
 58         tmp=tmp*tmp;
 59         n>>=1;
 60     }
 61     return ret;
 62 }
 63 struct Trie
 64 {
 65     int next[40][26],fail[40];
 66     bool end[40];
 67     int root,L;
 68     int newnode()
 69     {
 70         for(int i = 0;i < 26;i++)
 71             next[L][i] = -1;
 72         end[L++] = false;
 73         return L-1;
 74     }
 75     void init()
 76     {
 77         L = 0;
 78         root = newnode();
 79     }
 80     void insert(char buf[])
 81     {
 82         int len = strlen(buf);
 83         int now = root;
 84         for(int i = 0;i < len;i++)
 85         {
 86             if(next[now][buf[i]-‘a‘] == -1)
 87                 next[now][buf[i]-‘a‘] = newnode();
 88             now = next[now][buf[i]-‘a‘];
 89         }
 90         end[now] = true;
 91     }
 92     void build()
 93     {
 94         queue<int>Q;
 95         fail[root]=root;
 96         for(int i = 0;i < 26;i++)
 97             if(next[root][i] == -1)
 98                 next[root][i] = root;
 99             else
100             {
101                 fail[next[root][i]] = root;
102                 Q.push(next[root][i]);
103             }
104         while(!Q.empty())
105         {
106             int now = Q.front();
107             Q.pop();
108             if(end[fail[now]])end[now]=true;
109             for(int i = 0;i < 26;i++)
110                 if(next[now][i] == -1)
111                     next[now][i] = next[fail[now]][i];
112                 else
113                 {
114                     fail[next[now][i]] = next[fail[now]][i];
115                     Q.push(next[now][i]);
116                 }
117         }
118     }
119     Matrix getMatrix()
120     {
121         Matrix ret = Matrix(L+1);
122         for(int i = 0;i < L;i++)
123             for(int j = 0;j < 26;j++)
124                 if(end[next[i][j]]==false)
125                     ret.mat[i][next[i][j]] ++;
126         for(int i = 0;i < L+1;i++)
127             ret.mat[i][L] = 1;
128         return ret;
129     }
130     void debug()
131     {
132         for(int i = 0;i < L;i++)
133         {
134             printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
135             for(int j = 0;j < 26;j++)
136                 printf("%2d",next[i][j]);
137             printf("]\n");
138         }
139     }
140 };
141 char buf[10];
142 Trie ac;
143 int main()
144 {
145 //    freopen("in.txt","r",stdin);
146 //    freopen("out.txt","w",stdout);
147     int n,L;
148     while(scanf("%d%d",&n,&L)==2)
149     {
150         ac.init();
151         for(int i = 0;i < n;i++)
152         {
153             scanf("%s",buf);
154             ac.insert(buf);
155         }
156         ac.build();
157         Matrix a = ac.getMatrix();
158         a = pow_M(a,L);
159         unsigned long long res = 0;
160         for(int i = 0;i < a.n;i++)
161             res += a.mat[0][i];
162         res--;
163
164         /*
165          * f[n]=1 + 26^1 + 26^2 +...26^n
166          * f[n]=26*f[n-1]+1
167          * {f[n] 1} = {f[n-1] 1}[26 0;1 1]
168          * 数是f[L]-1;
169          * 此题的L<2^31.矩阵的幂不能是L+1次,否则就超时了
170          */
171         a = Matrix(2);
172         a.mat[0][0]=26;
173         a.mat[1][0] = a.mat[1][1] = 1;
174         a=pow_M(a,L);
175         unsigned long long ans=a.mat[1][0]+a.mat[0][0];
176         ans--;
177         ans-=res;
178         cout<<ans<<endl;
179     }
180     return 0;
181 }

7、POJ 1625 Censored!

AC自动机+DP+高精度

好题

题解here

//============================================================================
// Name        : POJ.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <queue>
#include <map>
using namespace std;
map<char,int>mp;
int N,M,P;
struct Matrix
{
    int mat[110][110];
    int n;
    Matrix(){}
    Matrix(int _n)
    {
        n=_n;
        for(int i = 0;i < n;i++)
            for(int j = 0;j < n;j++)
                mat[i][j] = 0;
    }
};
struct Trie
{
    int next[110][256],fail[110];
    bool end[110];
    int L,root;
    int newnode()
    {
        for(int i = 0;i < 256;i++)
            next[L][i] = -1;
        end[L++] = false;
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(char buf[])
    {
        int len = strlen(buf);
        int now = root;
        for(int i = 0;i < len;i++)
        {
            if(next[now][mp[buf[i]]] == -1)
                next[now][mp[buf[i]]] = newnode();
            now = next[now][mp[buf[i]]];
        }
        end[now] = true;
    }
    void build()
    {
        queue<int>Q;
        fail[root] = root;
        for(int i = 0;i < 256;i++)
            if(next[root][i] == -1)
                next[root][i] = root;
            else
            {
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();
            if(end[fail[now]]==true)end[now]=true;
            for(int i = 0;i < 256;i++)
                if(next[now][i] == -1)
                    next[now][i] = next[fail[now]][i];
                else
                {
                    fail[next[now][i]] = next[fail[now]][i];
                    Q.push(next[now][i]);
                }
        }
    }
    Matrix getMatrix()
    {
        Matrix res = Matrix(L);
        for(int i = 0;i < L;i++)
            for(int j = 0;j < N;j++)
                if(end[next[i][j]]==false)
                    res.mat[i][next[i][j]]++;
        return res;
    }
    void debug()
    {
        for(int i = 0;i < L;i++)
        {
            printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
            for(int j = 0;j < 26;j++)
                printf("%2d",next[i][j]);
            printf("]\n");
        }
    }

};

/*
 * 高精度,支持乘法和加法
 */
struct BigInt
{
    const static int mod = 10000;
    const static int DLEN = 4;
    int a[600],len;
    BigInt()
    {
        memset(a,0,sizeof(a));
        len = 1;
    }
    BigInt(int v)
    {
        memset(a,0,sizeof(a));
        len = 0;
        do
        {
            a[len++] = v%mod;
            v /= mod;
        }while(v);
    }
    BigInt(const char s[])
    {
        memset(a,0,sizeof(a));
        int L = strlen(s);
        len = L/DLEN;
        if(L%DLEN)len++;
        int index = 0;
        for(int i = L-1;i >= 0;i -= DLEN)
        {
            int t = 0;
            int k = i - DLEN + 1;
            if(k < 0)k = 0;
            for(int j = k;j <= i;j++)
                t = t*10 + s[j] - ‘0‘;
            a[index++] = t;
        }
    }
    BigInt operator +(const BigInt &b)const
    {
        BigInt res;
        res.len = max(len,b.len);
        for(int i = 0;i <= res.len;i++)
            res.a[i] = 0;
        for(int i = 0;i < res.len;i++)
        {
            res.a[i] += ((i < len)?a[i]:0)+((i < b.len)?b.a[i]:0);
            res.a[i+1] += res.a[i]/mod;
            res.a[i] %= mod;
        }
        if(res.a[res.len] > 0)res.len++;
        return res;
    }
    BigInt operator *(const BigInt &b)const
    {
        BigInt res;
        for(int i = 0; i < len;i++)
        {
            int up = 0;
            for(int j = 0;j < b.len;j++)
            {
                int temp = a[i]*b.a[j] + res.a[i+j] + up;
                res.a[i+j] = temp%mod;
                up = temp/mod;
            }
            if(up != 0)
                res.a[i + b.len] = up;
        }
        res.len = len + b.len;
        while(res.a[res.len - 1] == 0 &&res.len > 1)res.len--;
        return res;
    }
    void output()
    {
        printf("%d",a[len-1]);
        for(int i = len-2;i >=0 ;i--)
            printf("%04d",a[i]);
        printf("\n");
    }
};
char buf[1010];
BigInt dp[2][110];
Trie ac;
int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);

    while(scanf("%d%d%d",&N,&M,&P)==3)
    {
        gets(buf);
        gets(buf);
        mp.clear();
        int len = strlen(buf);
        for(int i = 0;i < len;i++)
            mp[buf[i]]=i;
        ac.init();
        for(int i = 0;i < P;i++)
        {
            gets(buf);
            ac.insert(buf);
        }
        ac.build();
//        ac.debug();
        Matrix a= ac.getMatrix();

//        for(int i = 0;i <a.n;i++)
//        {
//            for(int j=0;j<a.n;j++)printf("%d ",a.mat[i][j]);
//            cout<<endl;
//        }

        int now = 0;
        dp[now][0] = 1;
        for(int i = 1;i < a.n;i++)
            dp[now][i] = 0;
        for(int i = 0;i < M;i++)
        {
            now^=1;
            for(int j = 0;j < a.n;j++)
                dp[now][j] = 0;
            for(int j = 0;j < a.n;j++)
                for(int k = 0;k < a.n;k++)
                    if(a.mat[j][k] > 0)
                        dp[now][k] = dp[now][k]+dp[now^1][j]*a.mat[j][k];
//            for(int j = 0;j < a.n;j++)
//                dp[now][j].output();
        }
        BigInt ans = 0;
        for(int i = 0;i < a.n;i++)
            ans = ans + dp[now][i];
        ans.output();
    }
    return 0;
}

8、HDU 2825 Wireless Password

AC自动机+状态压缩DP

相当于在AC自动机上产生状态转移,然后进行dp

//============================================================================
// Name        : HDU.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
const int MOD=20090717;
int n,m,k;
int dp[30][110][1<<10];
int num[5000];

struct Trie
{
    int next[110][26],fail[110],end[110];
    int root,L;
    int newnode()
    {
        for(int i = 0;i < 26;i++)
            next[L][i] = -1;
        end[L++] = 0;
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(char buf[],int id)
    {
        int len = strlen(buf);
        int now = root;
        for(int i = 0;i < len;i++)
        {
            if(next[now][buf[i]-‘a‘]==-1)
                next[now][buf[i]-‘a‘] = newnode();
            now = next[now][buf[i]-‘a‘];
        }
        end[now] |= (1<<id);
    }
    void build()
    {
        queue<int>Q;
        fail[root] = root;
        for(int i = 0;i < 26;i++)
            if(next[root][i] == -1)
                next[root][i] = root;
            else
            {
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();
            end[now] |= end[fail[now]];
            for(int i = 0;i < 26;i++)
                if(next[now][i] == -1)
                    next[now][i] = next[fail[now]][i];
                else
                {
                    fail[next[now][i]] = next[fail[now]][i];
                    Q.push(next[now][i]);
                }
        }
    }
    int solve()
    {
        //memset(dp,0,sizeof(dp));
        for(int i = 0;i <= n;i++)
            for(int j = 0;j < L;j++)
                for(int p = 0;p < (1<<m);p++)
                    dp[i][j][p]=0;
        dp[0][0][0] = 1;
        for(int i = 0;i < n;i++)
            for(int j = 0;j < L;j++)
                for(int p = 0;p< (1<<m);p++)
                    if(dp[i][j][p] > 0)
                    {
                        for(int x = 0;x < 26;x++)
                        {
                            int newi = i+1;
                            int newj = next[j][x];
                            int newp = (p|end[newj]);
                            dp[newi][newj][newp] += dp[i][j][p];
                            dp[newi][newj][newp]%=MOD;
                        }
                    }
        int ans = 0;
        for(int p = 0;p < (1<<m);p++)
        {
            if(num[p] < k)continue;
            for(int i = 0;i < L;i++)
            {
                ans = (ans + dp[n][i][p])%MOD;
            }
        }
        return ans;
    }
};
char buf[20];
Trie ac;
int main()
{
    for(int i=0;i<(1<<10);i++)
    {
        num[i] = 0;
        for(int j = 0;j < 10;j++)
            if(i & (1<<j))
                num[i]++;
    }
    while(scanf("%d%d%d",&n,&m,&k)==3)
    {
        if(n== 0 && m==0 &&k==0)break;
        ac.init();
        for(int i = 0;i < m;i++)
        {
            scanf("%s",buf);
            ac.insert(buf,i);
        }
        ac.build();
        printf("%d\n",ac.solve());
    }
    return 0;
}

9、HDU 2296 Ring

需要输出字典序最小的解

在DP的时候加一个字符数组来记录就行了

//============================================================================
// Name        : HDU.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
using namespace std;

int a[110];
int dp[55][1110];
char str[55][1110][55];

bool cmp(char s1[],char s2[])
{
    int len1=strlen(s1);
    int len2=strlen(s2);
    if(len1 != len2)return len1 < len2;
    else return strcmp(s1,s2) < 0;
}

const int INF=0x3f3f3f3f;
struct Trie
{
    int next[1110][26],fail[1110],end[1110];
    int root,L;
    int newnode()
    {
        for(int i = 0;i < 26;i++)
            next[L][i] = -1;
        end[L++] = -1;
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(char buf[],int id)
    {
        int len = strlen(buf);
        int now = root;
        for(int i = 0;i < len;i++)
        {
            if(next[now][buf[i]-‘a‘] == -1)
                next[now][buf[i]-‘a‘] = newnode();
            now = next[now][buf[i]-‘a‘];
        }
        end[now] = id;
    }
    void build()
    {
        queue<int>Q;
        fail[root] = root;
        for(int i = 0;i < 26;i++)
            if(next[root][i] == -1)
                next[root][i] = root;
            else
            {
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();
            for(int i = 0;i < 26;i++)
                if(next[now][i] == -1)
                    next[now][i] = next[fail[now]][i];
                else
                {
                    fail[next[now][i]] = next[fail[now]][i];
                    Q.push(next[now][i]);
                }
        }
    }
    void solve(int n)
    {
        for(int i = 0;i <= n;i++)
            for(int j = 0;j < L;j++)
                dp[i][j] = -INF;
        dp[0][0] = 0;
        strcpy(str[0][0],"");
        char ans[55];
        strcpy(ans,"");
        int Max = 0;
        char tmp[55];
        for(int i = 0; i < n;i++)
            for(int j = 0;j < L;j++)
                if(dp[i][j]>=0)
                {
                    strcpy(tmp,str[i][j]);
                    int len = strlen(tmp);
                    for(int k = 0;k < 26;k++)
                    {
                        int nxt=next[j][k];
                        tmp[len] = ‘a‘+k;
                        tmp[len+1] = 0;
                        int tt = dp[i][j];
                        if(end[nxt] != -1)
                            tt+=a[end[nxt]];

                        if(dp[i+1][nxt]<tt || (dp[i+1][nxt]==tt && cmp(tmp,str[i+1][nxt])))
                        {
                            dp[i+1][nxt] = tt;
                            strcpy(str[i+1][nxt],tmp);
                            if(tt > Max ||(tt==Max && cmp(tmp,ans)))
                            {
                                Max = tt;
                                strcpy(ans,tmp);
                            }
                        }
                    }
                }
        printf("%s\n",ans);
    }
};
char buf[60];
Trie ac;
int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int T;
    int n,m;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        ac.init();
        for(int i = 0;i < m;i++)
        {
            scanf("%s",buf);
            ac.insert(buf,i);
        }
        for(int i = 0;i < m;i++)
            scanf("%d",&a[i]);
        ac.build();
        ac.solve(n);
    }
    return 0;
}

10、HDU 2457 DNA repair

很简单的AC自动机+DP了

  1 //============================================================================
  2 // Name        : HDU.cpp
  3 // Author      :
  4 // Version     :
  5 // Copyright   : Your copyright notice
  6 // Description : Hello World in C++, Ansi-style
  7 //============================================================================
  8
  9 #include <iostream>
 10 #include <string.h>
 11 #include <stdio.h>
 12 #include <algorithm>
 13 #include <queue>
 14 using namespace std;
 15 const int INF = 0x3f3f3f3f;
 16 struct Trie
 17 {
 18     int next[1010][4],fail[1010];
 19     bool end[1010];
 20     int root,L;
 21     int newnode()
 22     {
 23         for(int i = 0;i < 4;i++)
 24             next[L][i] = -1;
 25         end[L++] = false;
 26         return L-1;
 27     }
 28     void init()
 29     {
 30         L = 0;
 31         root = newnode();
 32     }
 33     int getch(char ch)
 34     {
 35         if(ch == ‘A‘)return 0;
 36         else if(ch == ‘C‘)return 1;
 37         else if(ch == ‘G‘)return 2;
 38         else if(ch == ‘T‘)return 3;
 39     }
 40     void insert(char buf[])
 41     {
 42         int len = strlen(buf);
 43         int now = root;
 44         for(int i = 0;i < len;i++)
 45         {
 46             if(next[now][getch(buf[i])] == -1)
 47                 next[now][getch(buf[i])] = newnode();
 48             now = next[now][getch(buf[i])];
 49         }
 50         end[now] = true;
 51     }
 52     void build()
 53     {
 54         queue<int>Q;
 55         fail[root] = root;
 56         for(int i = 0;i < 4;i++)
 57             if(next[root][i] == -1)
 58                 next[root][i] = root;
 59             else
 60             {
 61                 fail[next[root][i]] = root;
 62                 Q.push(next[root][i]);
 63             }
 64         while(!Q.empty())
 65         {
 66             int now = Q.front();
 67             Q.pop();
 68             if(end[fail[now]])end[now] = true;//这里不要忘记
 69             for(int i = 0;i < 4;i++)
 70                 if(next[now][i] == -1)
 71                     next[now][i] = next[fail[now]][i];
 72                 else
 73                 {
 74                     fail[next[now][i]] = next[fail[now]][i];
 75                     Q.push(next[now][i]);
 76                 }
 77         }
 78     }
 79     int dp[1010][1010];
 80     int solve(char buf[])
 81     {
 82         int len = strlen(buf);
 83         for(int i = 0;i <= len;i++)
 84             for(int j = 0;j < L;j++)
 85                 dp[i][j] = INF;
 86         dp[0][root] = 0;
 87         for(int i = 0;i < len;i++)
 88             for(int j = 0;j < L;j++)
 89                 if(dp[i][j] < INF)
 90                 {
 91                     for(int k = 0;k < 4;k++)
 92                     {
 93                         int news = next[j][k];
 94                         if(end[news])continue;
 95                         int tmp;
 96                         if( k == getch(buf[i]))tmp = dp[i][j];
 97                         else tmp = dp[i][j] + 1;
 98                         dp[i+1][news] = min(dp[i+1][news],tmp);
 99                     }
100                 }
101         int ans = INF;
102         for(int j = 0;j < L;j++)
103             ans = min(ans,dp[len][j]);
104         if(ans == INF)ans = -1;
105         return ans;
106     }
107
108 };
109 char buf[1010];
110 Trie ac;
111 int main()
112 {
113     int n;
114     int iCase = 0;
115     while ( scanf("%d",&n) == 1 && n)
116     {
117         iCase++;
118         ac.init();
119         while(n--)
120         {
121             scanf("%s",buf);
122             ac.insert(buf);
123         }
124         ac.build();
125         scanf("%s",buf);
126         printf("Case %d: %d\n",iCase,ac.solve(buf));
127     }
128     return 0;
129 }

11、ZOJ 3228 Searching the String

这题需要查询两种,一种是可重叠,一种是不可重叠的。

找模式串在目标串中的出现次数。

加一个数组记录上一次出现的位置,然后就可以求出不可重叠的了

  1 //============================================================================
  2 // Name        : ZOJ.cpp
  3 // Author      :
  4 // Version     :
  5 // Copyright   : Your copyright notice
  6 // Description : Hello World in C++, Ansi-style
  7 //============================================================================
  8
  9 #include <iostream>
 10 #include <stdio.h>
 11 #include <string.h>
 12 #include <algorithm>
 13 #include <queue>
 14 using namespace std;
 15
 16 struct Trie
 17 {
 18     int next[600010][26],fail[600010],deep[600010];
 19     int root,L;
 20     int newnode()
 21     {
 22         for(int i = 0;i < 26;i++)
 23             next[L][i] = -1;
 24         L++;
 25         return L-1;
 26     }
 27     void init()
 28     {
 29         L = 0;
 30         root = newnode();
 31         deep[root] = 0;
 32     }
 33     int insert(char buf[])
 34     {
 35         int len = strlen(buf);
 36         int now = root;
 37         for(int i = 0;i < len;i++)
 38         {
 39             if(next[now][buf[i]-‘a‘] == -1)
 40             {
 41                 next[now][buf[i]-‘a‘] = newnode();
 42                 deep[ next[now][buf[i]-‘a‘] ] = i+1;
 43             }
 44             now = next[now][buf[i]-‘a‘];
 45         }
 46         return now;
 47     }
 48     void build()
 49     {
 50         queue<int>Q;
 51         fail[root] = root;
 52         for(int i = 0;i < 26;i++)
 53             if(next[root][i] == -1)
 54                 next[root][i] = root;
 55             else
 56             {
 57                 fail[next[root][i]] = root;
 58                 Q.push(next[root][i]);
 59             }
 60         while(!Q.empty())
 61         {
 62             int now = Q.front();
 63             Q.pop();
 64             for(int i = 0;i < 26;i++)
 65                 if(next[now][i] == -1)
 66                     next[now][i] = next[fail[now]][i];
 67                 else
 68                 {
 69                     fail[next[now][i]] = next[fail[now]][i];
 70                     Q.push(next[now][i]);
 71                 }
 72         }
 73     }
 74     int cnt[600010][2];
 75     int last[600010];
 76     void query(char buf[])
 77     {
 78         int len = strlen(buf);
 79         int now = root;
 80         memset(cnt,0,sizeof(cnt));
 81         memset(last,-1,sizeof(last));
 82         for(int i = 0;i < len;i++)
 83         {
 84             now = next[now][buf[i]-‘a‘];
 85             int temp = now;
 86             while(temp != root)
 87             {
 88                 cnt[temp][0]++;
 89                 if(i - last[temp] >= deep[temp])
 90                 {
 91                     last[temp] = i;
 92                     cnt[temp][1]++;
 93                 }
 94                 temp = fail[temp];
 95             }
 96         }
 97     }
 98 };
 99 Trie ac;
100 char str[100010];
101 char buf[20];
102 int typ[100010],pos[100010];
103 int main()
104 {
105 //    freopen("in.txt","r",stdin);
106 //    freopen("out.txt","w",stdout);
107     int n;
108     int iCase = 0;
109     while(scanf("%s",str)==1)
110     {
111         iCase++;
112         printf("Case %d\n",iCase);
113         scanf("%d",&n);
114         ac.init();
115         for(int i = 0;i < n;i++)
116         {
117             scanf("%d%s",&typ[i],buf);
118             pos[i]=ac.insert(buf);
119         }
120         ac.build();
121         ac.query(str);
122         for(int i = 0;i < n;i++)
123             printf("%d\n",ac.cnt[pos[i]][typ[i]]);
124         printf("\n");
125     }
126     return 0;
127 }

12、HDU 3341 Lost‘s revenge

这题主要是状态的表示,就是记录ACGT出现的次数。

然后这个ACGT次数表示的时候,状态要转化。

题解here

  1 //============================================================================
  2 // Name        : HDU.cpp
  3 // Author      :
  4 // Version     :
  5 // Copyright   : Your copyright notice
  6 // Description : Hello World in C++, Ansi-style
  7 //============================================================================
  8
  9 #include <iostream>
 10 #include <string.h>
 11 #include <stdio.h>
 12 #include <algorithm>
 13 #include <queue>
 14 using namespace std;
 15 const int INF = 0x3f3f3f3f;
 16 struct Trie
 17 {
 18     int next[510][4],fail[510];
 19     int end[510];
 20     int root,L;
 21     int newnode()
 22     {
 23         for(int i = 0;i < 4;i++)
 24             next[L][i] = -1;
 25         end[L++] = 0;
 26         return L-1;
 27     }
 28     void init()
 29     {
 30         L = 0;
 31         root = newnode();
 32     }
 33     int getch(char ch)
 34     {
 35         if(ch == ‘A‘)return 0;
 36         else if(ch == ‘C‘)return 1;
 37         else if(ch == ‘G‘)return 2;
 38         else return 3;
 39     }
 40     void insert(char buf[])
 41     {
 42         int len = strlen(buf);
 43         int now = root;
 44         for(int i = 0;i < len;i++)
 45         {
 46             if(next[now][getch(buf[i])] == -1)
 47                 next[now][getch(buf[i])] = newnode();
 48             now = next[now][getch(buf[i])];
 49         }
 50         end[now] ++;
 51     }
 52     void build()
 53     {
 54         queue<int>Q;
 55         fail[root] = root;
 56         for(int i = 0;i < 4;i++)
 57             if(next[root][i] == -1)
 58                 next[root][i] = root;
 59             else
 60             {
 61                 fail[next[root][i]] = root;
 62                 Q.push(next[root][i]);
 63             }
 64         while(!Q.empty())
 65         {
 66             int now = Q.front();
 67             Q.pop();
 68             end[now] += end[fail[now]];/********/
 69             for(int i = 0;i < 4;i++)
 70                 if(next[now][i] == -1)
 71                     next[now][i] = next[fail[now]][i];
 72                 else
 73                 {
 74                     fail[next[now][i]] = next[fail[now]][i];
 75                     Q.push(next[now][i]);
 76                 }
 77         }
 78     }
 79     int dp[510][11*11*11*11+5];
 80     int bit[4];
 81     int num[4];
 82     int solve(char buf[])
 83     {
 84         int len = strlen(buf);
 85         memset(num,0,sizeof(num));
 86         for(int i = 0;i < len;i++)
 87             num[getch(buf[i])]++;
 88         bit[0] = (num[1]+1)*(num[2]+1)*(num[3]+1);
 89         bit[1] = (num[2]+1)*(num[3]+1);
 90         bit[2] = (num[3]+1);
 91         bit[3] = 1;
 92         memset(dp,-1,sizeof(dp));
 93         dp[root][0] = 0;
 94         for(int A = 0;A <= num[0];A++)
 95             for(int B = 0;B <= num[1];B++)
 96                 for(int C = 0;C <= num[2];C++)
 97                     for(int D = 0;D <= num[3];D++)
 98                     {
 99                         int s = A*bit[0] + B*bit[1] + C*bit[2] + D*bit[3];
100                         for(int i = 0;i < L;i++)
101                             if(dp[i][s] >= 0)
102                             {
103                                 for(int k = 0;k < 4;k++)
104                                 {
105                                     if(k == 0 && A == num[0])continue;
106                                     if(k == 1 && B == num[1])continue;
107                                     if(k == 2 && C == num[2])continue;
108                                     if(k == 3 && D == num[3])continue;
109                                     dp[next[i][k]][s+bit[k]] = max(dp[next[i][k]][s+bit[k]],dp[i][s]+end[next[i][k]]);
110                                 }
111                             }
112                     }
113         int ans = 0;
114         int status = num[0]*bit[0] + num[1]*bit[1] + num[2]*bit[2] + num[3]*bit[3];
115         for(int i = 0;i < L;i++)
116             ans = max(ans,dp[i][status]);
117         return ans;
118     }
119 };
120 char buf[50];
121 Trie ac;
122 int main()
123 {
124 //    freopen("in.txt","r",stdin);
125 //    freopen("out.txt","w",stdout);
126     int n;
127     int iCase = 0;
128     while( scanf("%d",&n) == 1 && n)
129     {
130         iCase++;
131         ac.init();
132         for(int i = 0;i < n;i++)
133         {
134             scanf("%s",buf);
135             ac.insert(buf);
136         }
137         ac.build();
138         scanf("%s",buf);
139         printf("Case %d: %d\n",iCase,ac.solve(buf));
140     }
141     return 0;
142 }

13、HDU 3247 Resource Archiver

使用最短路预处理出状态的转移。这样可以优化很多

  1 //============================================================================
  2 // Name        : HDU.cpp
  3 // Author      :
  4 // Version     :
  5 // Copyright   : Your copyright notice
  6 // Description : Hello World in C++, Ansi-style
  7 //============================================================================
  8
  9 #include <iostream>
 10 #include <stdio.h>
 11 #include <string.h>
 12 #include <algorithm>
 13 #include <queue>
 14 using namespace std;
 15
 16 const int INF = 0x3f3f3f3f;
 17
 18 struct Trie
 19 {
 20     int next[60010][2],fail[60010],end[60010];
 21     int root,L;
 22     int newnode()
 23     {
 24         for(int i = 0;i < 2;i++)
 25             next[L][i] = -1;
 26         end[L++] = 0;
 27         return L-1;
 28     }
 29     void init()
 30     {
 31         L = 0;
 32         root = newnode();
 33     }
 34     void insert(char buf[],int id)
 35     {
 36         int len = strlen(buf);
 37         int now = root;
 38         for(int i = 0;i < len ;i++)
 39         {
 40             if(next[now][buf[i]-‘0‘] == -1)
 41                 next[now][buf[i]-‘0‘] = newnode();
 42             now = next[now][buf[i]-‘0‘];
 43         }
 44         end[now] = id;
 45     }
 46     void build()
 47     {
 48         queue<int>Q;
 49         fail[root] = root;
 50         for(int i = 0;i < 2;i++)
 51             if(next[root][i] == -1)
 52                 next[root][i] = root;
 53             else
 54             {
 55                 fail[next[root][i]] = root;
 56                 Q.push(next[root][i]);
 57             }
 58         while( !Q.empty() )
 59         {
 60             int now = Q.front();
 61             Q.pop();
 62             if(end[fail[now]] == -1)end[now] = -1;
 63             else end[now] |= end[fail[now]];
 64             for(int i = 0;i < 2;i++)
 65                 if(next[now][i] == -1)
 66                     next[now][i] = next[fail[now]][i];
 67                 else
 68                 {
 69                     fail[next[now][i]] = next[fail[now]][i];
 70                     Q.push(next[now][i]);
 71                 }
 72         }
 73     }
 74     int g[11][11];
 75     int dp[1025][11];
 76     int cnt;
 77     int pos[11];
 78     int dis[60010];
 79
 80
 81     void bfs(int k)
 82     {
 83         queue<int>q;
 84         memset(dis,-1,sizeof(dis));
 85         dis[pos[k]] = 0;
 86         q.push(pos[k]);
 87         while(!q.empty())
 88         {
 89             int now = q.front();
 90             q.pop();
 91             for(int i = 0; i< 2;i++)
 92             {
 93                 int tmp = next[now][i];
 94                 if(dis[tmp]<0 && end[tmp] >= 0)
 95                 {
 96                     dis[tmp] = dis[now] + 1;
 97                     q.push(tmp);
 98                 }
 99             }
100         }
101         for(int i = 0;i < cnt;i++)
102             g[k][i] = dis[pos[i]];
103     }
104
105
106     int solve(int n)
107     {
108
109         pos[0] = 0;
110         cnt = 1;
111         for(int i = 0;i < L;i++)
112             if(end[i] > 0)
113                 pos[cnt++] = i;
114         for(int i = 0; i < cnt;i++)
115             bfs(i);
116
117         for(int i = 0;i < (1<<n);i++)
118             for(int j = 0;j < cnt;j++)
119                 dp[i][j] = INF;
120         dp[0][0] = 0;
121         for(int i = 0;i <(1<<n);i++)
122             for(int j = 0;j < cnt;j++)
123                 if(dp[i][j]<INF)
124                 {
125                     for(int k = 0;k < cnt;k++)
126                     {
127                         if(g[j][k] < 0)continue;
128                         if( j == k)continue;
129                         dp[i|end[pos[k]]][k] = min(dp[i|end[pos[k]]][k],dp[i][j]+g[j][k]);
130                     }
131                 }
132         int ans = INF;
133         for(int j = 0;j < cnt;j++)
134             ans = min(ans,dp[(1<<n)-1][j]);
135         return ans;
136     }
137 };
138 Trie ac;
139 char buf[1010];
140
141 int main()
142 {
143 //    freopen("in.txt","r",stdin);
144 //    freopen("out.txt","w",stdout);
145     int n,m;
146     while(scanf("%d%d",&n,&m) == 2)
147     {
148         if(n == 0 && m == 0)break;
149         ac.init();
150         for(int i = 0;i < n;i++)
151         {
152             scanf("%s",buf);
153             ac.insert(buf,1<<i);
154         }
155         for(int i = 0;i < m;i++)
156         {
157             scanf("%s",buf);
158             ac.insert(buf,-1);
159         }
160         ac.build();
161         printf("%d\n",ac.solve(n));
162     }
163     return 0;
164 }

14、ZOJ 3494 BCD Code

这道题很神,数位DP和AC自动机结合,太强大了。

题解here

  1 //============================================================================
  2 // Name        : ZOJ.cpp
  3 // Author      :
  4 // Version     :
  5 // Copyright   : Your copyright notice
  6 // Description : Hello World in C++, Ansi-style
  7 //============================================================================
  8
  9 #include <iostream>
 10 #include <stdio.h>
 11 #include <string.h>
 12 #include <algorithm>
 13 #include <queue>
 14 using namespace std;
 15
 16 struct Trie
 17 {
 18     int next[2010][2],fail[2010];
 19     bool end[2010];
 20     int root,L;
 21     int newnode()
 22     {
 23         for(int i = 0;i < 2;i++)
 24             next[L][i] = -1;
 25         end[L++] = false;
 26         return L-1;
 27     }
 28     void init()
 29     {
 30         L = 0;
 31         root = newnode();
 32     }
 33     void insert(char buf[])
 34     {
 35         int len = strlen(buf);
 36         int now = root;
 37         for(int i = 0;i < len ;i++)
 38         {
 39             if(next[now][buf[i]-‘0‘] == -1)
 40                 next[now][buf[i]-‘0‘] = newnode();
 41             now = next[now][buf[i]-‘0‘];
 42         }
 43         end[now] = true;
 44     }
 45     void build()
 46     {
 47         queue<int>Q;
 48         fail[root] = root;
 49         for(int i = 0;i < 2;i++)
 50             if(next[root][i] == -1)
 51                 next[root][i] = root;
 52             else
 53             {
 54                 fail[next[root][i]] = root;
 55                 Q.push(next[root][i]);
 56             }
 57         while(!Q.empty())
 58         {
 59             int now = Q.front();
 60             Q.pop();
 61             if(end[fail[now]])end[now] = true;
 62             for(int i = 0;i < 2;i++)
 63                 if(next[now][i] == -1)
 64                     next[now][i] = next[fail[now]][i];
 65                 else
 66                 {
 67                     fail[next[now][i]] = next[fail[now]][i];
 68                     Q.push(next[now][i]);
 69                 }
 70         }
 71     }
 72 };
 73 Trie ac;
 74
 75 int bcd[2010][10];
 76 int change(int pre,int num)
 77 {
 78     if(ac.end[pre])return -1;
 79     int cur = pre;
 80     for(int i = 3;i >= 0;i--)
 81     {
 82         if(ac.end[ac.next[cur][(num>>i)&1]])return -1;
 83         cur = ac.next[cur][(num>>i)&1];
 84     }
 85     return cur;
 86 }
 87 void pre_init()
 88 {
 89     for(int i = 0;i <ac.L;i++)
 90         for(int j = 0;j <10;j++)
 91             bcd[i][j] = change(i,j);
 92 }
 93 const int MOD = 1000000009;
 94 long long dp[210][2010];
 95 int bit[210];
 96
 97 long long dfs(int pos,int s,bool flag,bool z)
 98 {
 99     if(pos == -1)return 1;
100     if(!flag && dp[pos][s]!=-1)return dp[pos][s];
101     long long ans = 0;
102     if(z)
103     {
104         ans += dfs(pos-1,s,flag && bit[pos]==0,true);
105         ans %= MOD;
106     }
107     else
108     {
109         if(bcd[s][0]!=-1)ans += dfs(pos-1,bcd[s][0],flag && bit[pos]==0,false);
110         ans %= MOD;
111     }
112     int end = flag?bit[pos]:9;
113     for(int i = 1;i<=end;i++)
114     {
115         if(bcd[s][i]!=-1)
116         {
117             ans += dfs(pos-1,bcd[s][i],flag&&i==end,false);
118             ans %=MOD;
119         }
120     }
121     if(!flag && !z)dp[pos][s] = ans;
122     return ans;
123 }
124
125 long long calc(char s[])
126 {
127     int len = strlen(s);
128     for(int i = 0;i < len;i++)
129         bit[i] = s[len-1-i]-‘0‘;
130     return dfs(len-1,0,1,1);
131 }
132 char str[210];
133 int main()
134 {
135 //    freopen("in.txt","r",stdin);
136 //    freopen("out.txt","w",stdout);
137     int T;
138     scanf("%d",&T);
139     int n;
140     while(T--)
141     {
142         ac.init();
143         scanf("%d",&n);
144         for(int i = 0;i < n;i++)
145         {
146             scanf("%s",str);
147             ac.insert(str);
148         }
149         ac.build();
150         pre_init();
151         memset(dp,-1,sizeof(dp));
152         int ans = 0;
153         scanf("%s",str);
154         int len = strlen(str);
155         for(int i = len -1;i >=0;i--)
156         {
157             if(str[i]>‘0‘)
158             {
159                 str[i]--;
160                 break;
161             }
162             else str[i] = ‘9‘;
163         }
164         ans -= calc(str);
165         ans %=MOD;
166         scanf("%s",str);
167         ans += calc(str);
168         ans %=MOD;
169         if(ans < 0)ans += MOD;
170         printf("%d\n",ans);
171     }
172     return 0;
173 }

时间: 2024-10-13 16:16:27

转自kuangbin的AC自动机(赛前最后一博)的相关文章

【HDU 5384】Danganronpa(AC自动机)

看官方题解貌似就是个自动机裸题 比赛的时候用kuangbin的AC自动机模板瞎搞的,竟然A了,而且跑的还不慢.. 存下模板吧 #include<cstdio> #include<cstring> #include<string> #include<queue> #include<vector> #include<iostream> #include<algorithm> using namespace std; const

hdu5880 (AC自动机)

题目链接:hdu5880 Family View 题意:敏感词屏蔽,给一堆敏感词,给一段文本,要求把文本中所有的敏感词用*代替. 题解:对敏感词建出AC自动机,在AC自动机上跑文本,就可以得到文本的每个前缀的最长匹配后缀,扫一遍即可得到结果. 弱弱的说我还不会用AC自动机啊,赛后补题先留下大神的模板吧... 再留个博客改天练练:http://www.cnblogs.com/kuangbin/p/3164106.html 1 #include<cstdio> 2 #include<algo

HDU2222 Keywords Search(AC自动机)

AC自动机是一种多模式匹配的算法.大概过程如下: 首先所有模式串构造一棵Trie树,Trie树上的每个非根结点都代表一个从根出发到该点路径的字符串. 然后每个结点都计算出其fail指针的值,这个fail指针就指向这个结点所表示字符串的最长存在的后缀所对应的结点,如果不存在就指向根:计算每个结点的fail用BFS,比如当前结点u出队要拓展并计算其孩子结点的fail,v是其第k个孩子,fail[v]的值就是某个fail[fail[fail...[u]]]存在第k孩子结点其第k个孩子结点,如果不存在f

AC自动机-HDU2222-模板题

http://acm.hdu.edu.cn/showproblem.php?pid=2222 一个AC自动机的模板题.用的kuangbin的模板,静态建Trie树.可能遇到MLE的情况要转动态建树. AC自动机的讲解看这里 http://blog.csdn.net/niushuai666/article/details/7002823 http://blog.csdn.net/mobius_strip/article/details/22549517 /*--------------------

AC自动机(AC automation)

字典树+KMP 参考自: http://www.cppblog.com/mythit/archive/2009/04/21/80633.html 1 const int MAXN = 26; //字典大小 2 3 //定义结点 4 struct node{ 5 node* fail; 6 node* child[MAXN]; 7 int count; 8 node(){ 9 fail = NULL; 10 count = 0; 11 memset(child, NULL, sizeof(chil

AC自动机及KMP练习

好久都没敲过KMP和AC自动机了.以前只会敲个kuangbin牌板子套题.现在重新写了自己的板子加深了印象.并且刷了一些题来增加自己的理解. KMP网上教程很多,但我的建议还是先看AC自动机(Trie图)的构造后再去理解.板子的话大家大同小异. 而AC自动机的构造则是推荐王贇的<Trie图的构建.活用与改进>. 前面的备用知识则是字典树.推荐董华星的<浅析字母树在信息学竞赛中的应用>.董聚聚不仅仅是介绍了字典树,包括一些常见的应用也有论述,介绍的挺详细的. 接下来就是刷题的部分了.

专题训练之AC自动机

推荐博客:http://www.cnblogs.com/kuangbin/p/3164106.html AC自动机小结 https://blog.csdn.net/creatorx/article/details/71100840 AC自动机最详细的解释 1.(HDOJ2222)http://acm.hdu.edu.cn/showproblem.php?pid=2222 题意:求目标串中出现了几个模式串. 分析:AC自动机模板题 1 #include<cstdio> 2 #include<

AC自动机--summer-work之我连模板题都做不出

这章对现在的我来说有点难,要是不写点东西,三天后怕是就一无所有了. 但写这个没有营养的blog的目的真的不是做题或提升,只是学习学习代码和理解一些概念. 现在对AC自动机的理解还十分浅薄,这里先贴上目前我看过的文章: 深入理解Aho-Corasick自动机算法 AC 自动机学习笔记 AC自动机相比Trie多了失配边,结点到结点间的状态转移,结点到根的状态转移. 这里fail的定义是:使当前字符失配时跳转到另一段从root开始每一个字符都与当前已匹配字符段某一个后缀完全相同且长度最大的位置继续匹配

KMP,Trie,AC自动机题目集

字符串算法并不多,KMP,trie,AC自动机就是其中几个最经典的.字符串的题目灵活多变也有许多套路,需要多做题才能体会.这里收集了许多前辈的题目做个集合,方便自己回忆. KMP题目:https://blog.csdn.net/qq_38891827/article/details/80501506 Trie树题目:https://blog.csdn.net/qq_38891827/article/details/80532462 AC自动机:模板https://www.luogu.org/bl