• 转自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("]
    ");
            }
        }
    };
    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
    ",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("
    ");
            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
    ",ans);
        }
        return 0;
    }
    View Code

    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
    ",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("]
    ");
    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 }
    View Code

    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
    ",ac.query(buf,tot,n));
    150         }
    151         printf("
    ");
    152     }
    153     return 0;
    154 }
    View Code

    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
    ",ans);
    166     }
    167     return 0;
    168 }
    View Code

    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("]
    ");
    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 }
    View Code

    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("]
    ");
            }
        }
    
    };
    
    
    /*
     * 高精度,支持乘法和加法
     */
    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("
    ");
        }
    };
    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;
    }
    View Code

    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
    ",ac.solve());
        }
        return 0;
    }
    View Code

    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
    ",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;
    }
    View Code

    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
    ",iCase,ac.solve(buf));
    127     }
    128     return 0;
    129 }
    View Code

    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
    ",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
    ",ac.cnt[pos[i]][typ[i]]);
    124         printf("
    ");
    125     }
    126     return 0;
    127 }
    View Code

    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
    ",iCase,ac.solve(buf));
    140     }
    141     return 0;
    142 }
    View Code

    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
    ",ac.solve(n));
    162     }
    163     return 0;
    164 }
    View Code

    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
    ",ans);
    171     }
    172     return 0;
    173 }
    View Code
  • 相关阅读:
    nodewebkit系列(00):什么是nodewebkit?
    浅析Chrome Packaged Apps
    C#实现飞信短信发送
    结束——2012年微软精英挑战赛
    Vue开发笔记 — Vue项目结构
    TOGAF
    笔记本安装CentOS8
    架构设计的10个核心原则
    Vue PDF文件预览vuepdf
    Druid中使用log4j2进行日志输出
  • 原文地址:https://www.cnblogs.com/13224ACMer/p/4873257.html
Copyright © 2020-2023  润新知