【原创】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数组记录,查询一次。

【原创】AC自动机小结
//======================

// 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;

}
View Code

2、HDU 2896 病毒侵袭   

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

题解here

【原创】AC自动机小结
//============================================================================

// 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;

}
View Code

3、HDU 3065 病毒侵袭持续中

 

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

【原创】AC自动机小结
//============================================================================

// 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;



char str[1010][100];

struct Trie

{

    int next[1010*50][128],fail[1010*50],end[1010*50];

    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]);

                }

        }

    }

    int num[1010];

    void query(char buf[],int n)

    {

        for(int i = 0;i < n;i++)

            num[i] = 0;

        int len=strlen(buf);

        int now=root;

        for(int i=0;i<len;i++)

        {

            now=next[now][buf[i]];

            int temp = now;

            while( temp != root )

            {

                if(end[temp] != -1)

                    num[end[temp]]++;

                temp = fail[temp];

            }

        }

        for(int i = 0;i < n;i++)

            if(num[i] > 0)

                printf("%s: %d\n",str[i],num[i]);

    }



};



char buf[2000010];

Trie ac;

void debug()

{

    for (int i = 0; i < ac.L; i++)

    {

        printf("id = %3d ,fail = %3d ,end = %3d, chi = [",i,ac.fail[i],ac.end[i]);

        for (int j = 0; j < 128; j++)

            printf("%2d ",ac.next[i][j]);

        printf("]\n");

    }

}

int main()

{

//    freopen("in.txt","r",stdin);

//    freopen("out.txt","w",stdout);

    int n;

    while(scanf("%d",&n) == 1)

    {

        ac.init();

        for(int i = 0;i < n;i++)

        {

            scanf("%s",str[i]);

            ac.insert(str[i],i);

        }

        ac.build();

        scanf("%s",buf);

        ac.query(buf,n);

    }

    return 0;

}
View Code

 

4、ZOJ 3430 Detect the Virus

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

求出现的模式串的种类数

分支需要256个

 

【原创】AC自动机小结
//============================================================================

// Name        : ZOJ.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;



struct Trie

{

    int next[520*64][256],fail[520*64],end[520*64];

    int root,L;

    int newnode()

    {

        for(int i = 0;i < 256;i++)

            next[L][i] = -1;

        end[L++] = -1;

        return L-1;

    }

    void init()

    {

        L = 0;

        root = newnode();

    }

    void insert(unsigned char buf[],int len,int id)

    {

        int now = root;

        for(int i = 0;i < len;i++)

        {

            if(next[now][buf[i]] == -1)

                next[now][buf[i]] = newnode();

            now = next[now][buf[i]];

        }

        end[now] = id;

    }

    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();

            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]);

                }

        }

    }

    bool used[520];

    int query(unsigned char buf[],int len,int n)

    {

        memset(used,false,sizeof(used));

        int now = root;

        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;

                temp = fail[temp];

            }

        }

        int res = 0;

        for(int i = 0;i < n;i++)

            if(used[i])

                res++;

        return res;

    }

};



unsigned char buf[2050];

int tot;

char str[4000];

unsigned char s[4000];

unsigned char Get(char ch)

{

    if( ch>='A'&&ch<='Z' )return ch-'A';

    if( ch>='a'&&ch<='z' )return ch-'a'+26;

    if( ch>='0'&&ch<='9' )return ch-'0'+52;

    if( ch=='+' )return 62;

    else return 63;

}

void change(unsigned char str[],int len)

{

    int t=0;

    for(int i=0;i<len;i+=4)

    {

        buf[t++]=((str[i]<<2)|(str[i+1]>>4));

        if(i+2 < len)

            buf[t++]=( (str[i+1]<<4)|(str[i+2]>>2) );

        if(i+3 < len)

            buf[t++]= ( (str[i+2]<<6)|str[i+3] );

    }

    tot=t;

}

Trie ac;

int main()

{

//    freopen("in.txt","r",stdin);

//    freopen("out.txt","w",stdout);

    int n,m;

    while(scanf("%d",&n) == 1)

    {

        ac.init();

        for(int i = 0;i < n;i++)

        {

            scanf("%s",str);

            int len = strlen(str);

            while(str[len-1]=='=')len--;

            for(int j = 0;j < len;j++)

            {

                s[j] = Get(str[j]);

            }

            change(s,len);

            ac.insert(buf,tot,i);

        }

        ac.build();

        scanf("%d",&m);

        while(m--)

        {

            scanf("%s",str);

            int len=strlen(str);

            while(str[len-1]=='=')len--;

            for(int j = 0;j < len;j++)

                s[j] = Get(str[j]);

            change(s,len);

            printf("%d\n",ac.query(buf,tot,n));

        }

        printf("\n");

    }

    return 0;

}
View Code

5、POJ 2778 DNA Sequence

AC自动机+矩阵加速

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

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

【原创】AC自动机小结
//============================================================================

// Name        : POJ.cpp

// Author      : 

// Version     :

// Copyright   : Your copyright notice

// Description : Hello World in C++, Ansi-style

//============================================================================



#include <iostream>

#include <stdio.h>

#include <algorithm>

#include <string.h>

#include <queue>

using namespace std;



const int MOD=100000;

struct Matrix

{

    int mat[110][110],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;

    }

    Matrix operator *(const Matrix &b)const

    {

        Matrix ret=Matrix(n);

        for(int i=0;i<n;i++)

            for(int j=0;j<n;j++)

                for(int k=0;k<n;k++)

                {

                    int tmp=(long long)mat[i][k]*b.mat[k][j]%MOD;

                    ret.mat[i][j]=(ret.mat[i][j]+tmp)%MOD;

                }

        return ret;

    }

};

struct Trie

{

    int next[110][4],fail[110];

    bool end[110];

    int root,L;

    int newnode()

    {

        for(int i=0;i<4;i++)

            next[L][i]=-1;

        end[L++]=false;

        return L-1;

    }

    void init()

    {

        L=0;

        root=newnode();

    }

    int getch(char ch)

    {

        switch(ch)

        {

        case 'A':

            return 0;

            break;

        case 'C':

            return 1;

            break;

        case 'G':

            return 2;

            break;

        case 'T':

            return 3;

            break;

        }

    }

    void insert(char s[])

    {

        int len=strlen(s);

        int now=root;

        for(int i = 0;i < len;i++)

        {

            if(next[now][getch(s[i])] == -1)

                next[now][getch(s[i])] = newnode();

            now = next[now][getch(s[i])];

        }

        end[now]=true;

    }

    void build()

    {

        queue<int>Q;

        for(int i = 0;i < 4;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 < 4;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<4;j++)

                if(end[next[i][j]]==false)

                    res.mat[i][next[i][j]]++;

        return res;

    }

};



Trie ac;

char buf[20];



Matrix pow_M(Matrix a,int n)

{

    Matrix ret = Matrix(a.n);

    for(int i = 0; i < ret.n; i++)

        ret.mat[i][i]=1;

    Matrix tmp=a;

    while(n)

    {

        if(n&1)ret=ret*tmp;

        tmp=tmp*tmp;

        n>>=1;

    }

    return ret;

}



int main()

{

    int n,m;

    while(scanf("%d%d",&n,&m) != EOF)

    {

        ac.init();

        for(int i=0;i<n;i++)

        {

            scanf("%s",buf);

            ac.insert(buf);

        }

        ac.build();

        Matrix a=ac.getMatrix();

        a=pow_M(a,m);

        int ans=0;

        for(int i=0;i<a.n;i++)

        {

            ans=(ans+a.mat[0][i])%MOD;

        }

        printf("%d\n",ans);

    }

    return 0;

}
View Code

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

 

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

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

题解here

【原创】AC自动机小结
//============================================================================

// 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;

struct Matrix

{

    unsigned long long mat[40][40];

    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;

    }

    Matrix operator *(const Matrix &b)const

    {

        Matrix ret = Matrix(n);

        for(int i=0;i<n;i++)

            for(int j=0;j<n;j++)

                for(int k=0;k<n;k++)

                    ret.mat[i][j]+=mat[i][k]*b.mat[k][j];

        return ret;

    }

};

unsigned long long pow_m(unsigned long long a,int n)

{

    unsigned long long ret=1;

    unsigned long long tmp = a;

    while(n)

    {

        if(n&1)ret*=tmp;

        tmp*=tmp;

        n>>=1;

    }

    return ret;

}

Matrix pow_M(Matrix a,int n)

{

    Matrix ret = Matrix(a.n);

    for(int i=0;i<a.n;i++)

        ret.mat[i][i] = 1;

    Matrix tmp = a;

    while(n)

    {

        if(n&1)ret=ret*tmp;

        tmp=tmp*tmp;

        n>>=1;

    }

    return ret;

}

struct Trie

{

    int next[40][26],fail[40];

    bool end[40];

    int root,L;

    int newnode()

    {

        for(int i = 0;i < 26;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][buf[i]-'a'] == -1)

                next[now][buf[i]-'a'] = newnode();

            now = next[now][buf[i]-'a'];

        }

        end[now] = true;

    }

    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();

            if(end[fail[now]])end[now]=true;

            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]);

                }

        }

    }

    Matrix getMatrix()

    {

        Matrix ret = Matrix(L+1);

        for(int i = 0;i < L;i++)

            for(int j = 0;j < 26;j++)

                if(end[next[i][j]]==false)

                    ret.mat[i][next[i][j]] ++;

        for(int i = 0;i < L+1;i++)

            ret.mat[i][L] = 1;

        return ret;

    }

    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[10];

Trie ac;

int main()

{

//    freopen("in.txt","r",stdin);

//    freopen("out.txt","w",stdout);

    int n,L;

    while(scanf("%d%d",&n,&L)==2)

    {

        ac.init();

        for(int i = 0;i < n;i++)

        {

            scanf("%s",buf);

            ac.insert(buf);

        }

        ac.build();

        Matrix a = ac.getMatrix();

        a = pow_M(a,L);

        unsigned long long res = 0;

        for(int i = 0;i < a.n;i++)

            res += a.mat[0][i];

        res--;



        /*

         * f[n]=1 + 26^1 + 26^2 +...26^n

         * f[n]=26*f[n-1]+1

         * {f[n] 1} = {f[n-1] 1}[26 0;1 1]

         * 数是f[L]-1;

         * 此题的L<2^31.矩阵的幂不能是L+1次,否则就超时了

         */

        a = Matrix(2);

        a.mat[0][0]=26;

        a.mat[1][0] = a.mat[1][1] = 1;

        a=pow_M(a,L);

        unsigned long long ans=a.mat[1][0]+a.mat[0][0];

        ans--;

        ans-=res;

        cout<<ans<<endl;

    }

    return 0;

}
View Code

7、POJ 1625 Censored!

 AC自动机+DP+高精度

好题

题解here

 

【原创】AC自动机小结
//============================================================================

// 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;

}
View Code

 

8、HDU 2825 Wireless Password

AC自动机+状态压缩DP

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

【原创】AC自动机小结
//============================================================================

// 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;

}
View Code

 

9、HDU 2296 Ring

需要输出字典序最小的解

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

【原创】AC自动机小结
//============================================================================

// 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;

}
View Code

 

10、HDU 2457 DNA repair

很简单的AC自动机+DP了

【原创】AC自动机小结
//============================================================================

// 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;

const int INF = 0x3f3f3f3f;

struct Trie

{

    int next[1010][4],fail[1010];

    bool end[1010];

    int root,L;

    int newnode()

    {

        for(int i = 0;i < 4;i++)

            next[L][i] = -1;

        end[L++] = false;

        return L-1;

    }

    void init()

    {

        L = 0;

        root = newnode();

    }

    int getch(char ch)

    {

        if(ch == 'A')return 0;

        else if(ch == 'C')return 1;

        else if(ch == 'G')return 2;

        else if(ch == 'T')return 3;

    }

    void insert(char buf[])

    {

        int len = strlen(buf);

        int now = root;

        for(int i = 0;i < len;i++)

        {

            if(next[now][getch(buf[i])] == -1)

                next[now][getch(buf[i])] = newnode();

            now = next[now][getch(buf[i])];

        }

        end[now] = true;

    }

    void build()

    {

        queue<int>Q;

        fail[root] = root;

        for(int i = 0;i < 4;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]])end[now] = true;//这里不要忘记

            for(int i = 0;i < 4;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 dp[1010][1010];

    int solve(char buf[])

    {

        int len = strlen(buf);

        for(int i = 0;i <= len;i++)

            for(int j = 0;j < L;j++)

                dp[i][j] = INF;

        dp[0][root] = 0;

        for(int i = 0;i < len;i++)

            for(int j = 0;j < L;j++)

                if(dp[i][j] < INF)

                {

                    for(int k = 0;k < 4;k++)

                    {

                        int news = next[j][k];

                        if(end[news])continue;

                        int tmp;

                        if( k == getch(buf[i]))tmp = dp[i][j];

                        else tmp = dp[i][j] + 1;

                        dp[i+1][news] = min(dp[i+1][news],tmp);

                    }

                }

        int ans = INF;

        for(int j = 0;j < L;j++)

            ans = min(ans,dp[len][j]);

        if(ans == INF)ans = -1;

        return ans;

    }



};

char buf[1010];

Trie ac;

int main()

{

    int n;

    int iCase = 0;

    while ( scanf("%d",&n) == 1 && n)

    {

        iCase++;

        ac.init();

        while(n--)

        {

            scanf("%s",buf);

            ac.insert(buf);

        }

        ac.build();

        scanf("%s",buf);

        printf("Case %d: %d\n",iCase,ac.solve(buf));

    }

    return 0;

}
View Code

 

11、ZOJ 3228 Searching the String

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

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

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

【原创】AC自动机小结
//============================================================================

// Name        : ZOJ.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;



struct Trie

{

    int next[600010][26],fail[600010],deep[600010];

    int root,L;

    int newnode()

    {

        for(int i = 0;i < 26;i++)

            next[L][i] = -1;

        L++;

        return L-1;

    }

    void init()

    {

        L = 0;

        root = newnode();

        deep[root] = 0;

    }

    int 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();

                deep[ next[now][buf[i]-'a'] ] = i+1;

            }

            now = next[now][buf[i]-'a'];

        }

        return 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 cnt[600010][2];

    int last[600010];

    void query(char buf[])

    {

        int len = strlen(buf);

        int now = root;

        memset(cnt,0,sizeof(cnt));

        memset(last,-1,sizeof(last));

        for(int i = 0;i < len;i++)

        {

            now = next[now][buf[i]-'a'];

            int temp = now;

            while(temp != root)

            {

                cnt[temp][0]++;

                if(i - last[temp] >= deep[temp])

                {

                    last[temp] = i;

                    cnt[temp][1]++;

                }

                temp = fail[temp];

            }

        }

    }

};

Trie ac;

char str[100010];

char buf[20];

int typ[100010],pos[100010];

int main()

{

//    freopen("in.txt","r",stdin);

//    freopen("out.txt","w",stdout);

    int n;

    int iCase = 0;

    while(scanf("%s",str)==1)

    {

        iCase++;

        printf("Case %d\n",iCase);

        scanf("%d",&n);

        ac.init();

        for(int i = 0;i < n;i++)

        {

            scanf("%d%s",&typ[i],buf);

            pos[i]=ac.insert(buf);

        }

        ac.build();

        ac.query(str);

        for(int i = 0;i < n;i++)

            printf("%d\n",ac.cnt[pos[i]][typ[i]]);

        printf("\n");

    }

    return 0;

}
View Code

 

12、HDU 3341 Lost's revenge

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

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

题解here

【原创】AC自动机小结
//============================================================================

// 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;

const int INF = 0x3f3f3f3f;

struct Trie

{

    int next[510][4],fail[510];

    int end[510];

    int root,L;

    int newnode()

    {

        for(int i = 0;i < 4;i++)

            next[L][i] = -1;

        end[L++] = 0;

        return L-1;

    }

    void init()

    {

        L = 0;

        root = newnode();

    }

    int getch(char ch)

    {

        if(ch == 'A')return 0;

        else if(ch == 'C')return 1;

        else if(ch == 'G')return 2;

        else return 3;

    }

    void insert(char buf[])

    {

        int len = strlen(buf);

        int now = root;

        for(int i = 0;i < len;i++)

        {

            if(next[now][getch(buf[i])] == -1)

                next[now][getch(buf[i])] = newnode();

            now = next[now][getch(buf[i])];

        }

        end[now] ++;

    }

    void build()

    {

        queue<int>Q;

        fail[root] = root;

        for(int i = 0;i < 4;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 < 4;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 dp[510][11*11*11*11+5];

    int bit[4];

    int num[4];

    int solve(char buf[])

    {

        int len = strlen(buf);

        memset(num,0,sizeof(num));

        for(int i = 0;i < len;i++)

            num[getch(buf[i])]++;

        bit[0] = (num[1]+1)*(num[2]+1)*(num[3]+1);

        bit[1] = (num[2]+1)*(num[3]+1);

        bit[2] = (num[3]+1);

        bit[3] = 1;

        memset(dp,-1,sizeof(dp));

        dp[root][0] = 0;

        for(int A = 0;A <= num[0];A++)

            for(int B = 0;B <= num[1];B++)

                for(int C = 0;C <= num[2];C++)

                    for(int D = 0;D <= num[3];D++)

                    {

                        int s = A*bit[0] + B*bit[1] + C*bit[2] + D*bit[3];

                        for(int i = 0;i < L;i++)

                            if(dp[i][s] >= 0)

                            {

                                for(int k = 0;k < 4;k++)

                                {

                                    if(k == 0 && A == num[0])continue;

                                    if(k == 1 && B == num[1])continue;

                                    if(k == 2 && C == num[2])continue;

                                    if(k == 3 && D == num[3])continue;

                                    dp[next[i][k]][s+bit[k]] = max(dp[next[i][k]][s+bit[k]],dp[i][s]+end[next[i][k]]);

                                }

                            }

                    }

        int ans = 0;

        int status = num[0]*bit[0] + num[1]*bit[1] + num[2]*bit[2] + num[3]*bit[3];

        for(int i = 0;i < L;i++)

            ans = max(ans,dp[i][status]);

        return ans;

    }

};

char buf[50];

Trie ac;

int main()

{

//    freopen("in.txt","r",stdin);

//    freopen("out.txt","w",stdout);

    int n;

    int iCase = 0;

    while( scanf("%d",&n) == 1 && n)

    {

        iCase++;

        ac.init();

        for(int i = 0;i < n;i++)

        {

            scanf("%s",buf);

            ac.insert(buf);

        }

        ac.build();

        scanf("%s",buf);

        printf("Case %d: %d\n",iCase,ac.solve(buf));

    }

    return 0;

}
View Code

 

13、HDU 3247 Resource Archiver

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

【原创】AC自动机小结
//============================================================================

// 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 INF = 0x3f3f3f3f;



struct Trie

{

    int next[60010][2],fail[60010],end[60010];

    int root,L;

    int newnode()

    {

        for(int i = 0;i < 2;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]-'0'] == -1)

                next[now][buf[i]-'0'] = newnode();

            now = next[now][buf[i]-'0'];

        }

        end[now] = id;

    }

    void build()

    {

        queue<int>Q;

        fail[root] = root;

        for(int i = 0;i < 2;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]] == -1)end[now] = -1;

            else end[now] |= end[fail[now]];

            for(int i = 0;i < 2;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 g[11][11];

    int dp[1025][11];

    int cnt;

    int pos[11];

    int dis[60010];





    void bfs(int k)

    {

        queue<int>q;

        memset(dis,-1,sizeof(dis));

        dis[pos[k]] = 0;

        q.push(pos[k]);

        while(!q.empty())

        {

            int now = q.front();

            q.pop();

            for(int i = 0; i< 2;i++)

            {

                int tmp = next[now][i];

                if(dis[tmp]<0 && end[tmp] >= 0)

                {

                    dis[tmp] = dis[now] + 1;

                    q.push(tmp);

                }

            }

        }

        for(int i = 0;i < cnt;i++)

            g[k][i] = dis[pos[i]];

    }





    int solve(int n)

    {



        pos[0] = 0;

        cnt = 1;

        for(int i = 0;i < L;i++)

            if(end[i] > 0)

                pos[cnt++] = i;

        for(int i = 0; i < cnt;i++)

            bfs(i);



        for(int i = 0;i < (1<<n);i++)

            for(int j = 0;j < cnt;j++)

                dp[i][j] = INF;

        dp[0][0] = 0;

        for(int i = 0;i <(1<<n);i++)

            for(int j = 0;j < cnt;j++)

                if(dp[i][j]<INF)

                {

                    for(int k = 0;k < cnt;k++)

                    {

                        if(g[j][k] < 0)continue;

                        if( j == k)continue;

                        dp[i|end[pos[k]]][k] = min(dp[i|end[pos[k]]][k],dp[i][j]+g[j][k]);

                    }

                }

        int ans = INF;

        for(int j = 0;j < cnt;j++)

            ans = min(ans,dp[(1<<n)-1][j]);

        return ans;

    }

};

Trie ac;

char buf[1010];



int main()

{

//    freopen("in.txt","r",stdin);

//    freopen("out.txt","w",stdout);

    int n,m;

    while(scanf("%d%d",&n,&m) == 2)

    {

        if(n == 0 && m == 0)break;

        ac.init();

        for(int i = 0;i < n;i++)

        {

            scanf("%s",buf);

            ac.insert(buf,1<<i);

        }

        for(int i = 0;i < m;i++)

        {

            scanf("%s",buf);

            ac.insert(buf,-1);

        }

        ac.build();

        printf("%d\n",ac.solve(n));

    }

    return 0;

}
View Code

 

14、ZOJ 3494 BCD Code

 

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

题解here

【原创】AC自动机小结
//============================================================================

// Name        : ZOJ.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;



struct Trie

{

    int next[2010][2],fail[2010];

    bool end[2010];

    int root,L;

    int newnode()

    {

        for(int i = 0;i < 2;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][buf[i]-'0'] == -1)

                next[now][buf[i]-'0'] = newnode();

            now = next[now][buf[i]-'0'];

        }

        end[now] = true;

    }

    void build()

    {

        queue<int>Q;

        fail[root] = root;

        for(int i = 0;i < 2;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]])end[now] = true;

            for(int i = 0;i < 2;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]);

                }

        }

    }

};

Trie ac;



int bcd[2010][10];

int change(int pre,int num)

{

    if(ac.end[pre])return -1;

    int cur = pre;

    for(int i = 3;i >= 0;i--)

    {

        if(ac.end[ac.next[cur][(num>>i)&1]])return -1;

        cur = ac.next[cur][(num>>i)&1];

    }

    return cur;

}

void pre_init()

{

    for(int i = 0;i <ac.L;i++)

        for(int j = 0;j <10;j++)

            bcd[i][j] = change(i,j);

}

const int MOD = 1000000009;

long long dp[210][2010];

int bit[210];



long long dfs(int pos,int s,bool flag,bool z)

{

    if(pos == -1)return 1;

    if(!flag && dp[pos][s]!=-1)return dp[pos][s];

    long long ans = 0;

    if(z)

    {

        ans += dfs(pos-1,s,flag && bit[pos]==0,true);

        ans %= MOD;

    }

    else

    {

        if(bcd[s][0]!=-1)ans += dfs(pos-1,bcd[s][0],flag && bit[pos]==0,false);

        ans %= MOD;

    }

    int end = flag?bit[pos]:9;

    for(int i = 1;i<=end;i++)

    {

        if(bcd[s][i]!=-1)

        {

            ans += dfs(pos-1,bcd[s][i],flag&&i==end,false);

            ans %=MOD;

        }

    }

    if(!flag && !z)dp[pos][s] = ans;

    return ans;

}



long long calc(char s[])

{

    int len = strlen(s);

    for(int i = 0;i < len;i++)

        bit[i] = s[len-1-i]-'0';

    return dfs(len-1,0,1,1);

}

char str[210];

int main()

{

//    freopen("in.txt","r",stdin);

//    freopen("out.txt","w",stdout);

    int T;

    scanf("%d",&T);

    int n;

    while(T--)

    {

        ac.init();

        scanf("%d",&n);

        for(int i = 0;i < n;i++)

        {

            scanf("%s",str);

            ac.insert(str);

        }

        ac.build();

        pre_init();

        memset(dp,-1,sizeof(dp));

        int ans = 0;

        scanf("%s",str);

        int len = strlen(str);

        for(int i = len -1;i >=0;i--)

        {

            if(str[i]>'0')

            {

                str[i]--;

                break;

            }

            else str[i] = '9';

        }

        ans -= calc(str);

        ans %=MOD;

        scanf("%s",str);

        ans += calc(str);

        ans %=MOD;

        if(ans < 0)ans += MOD;

        printf("%d\n",ans);

    }

    return 0;

}
View Code

 

 

 

先简单总结到这吧!抱歉,时间原因,写得很简单,以后有机会好好补充完全吧!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(AC自动机)