AC自动机专题

首先献上模板:http://www.cnblogs.com/E-star/archive/2013/03/08/2950191.html

多模式串匹配:

HDU 2222 Keywords Search

http://acm.hdu.edu.cn/showproblem.php?pid=2222

题意:

http://www.cnblogs.com/E-star/archive/2013/02/19/2917212.html 这个链接是之前用指针形式做的,

下面是数组模拟:

View Code
#include <iostream>

#include <cstdio>

#include <cmath>

#include <vector>

#include <cstring>

#include <algorithm>

#include <string>

#include <set>

#include <functional>

#include <numeric>

#include <sstream>

#include <stack>

#include <map>

#include <queue>



#define CL(arr, val)    memset(arr, val, sizeof(arr))



#define ll long long

#define inf 0x7f7f7f7f

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)



#define L(x)    (x) << 1

#define R(x)    (x) << 1 | 1

#define MID(l, r)   (l + r) >> 1

#define Min(x, y)   (x) < (y) ? (x) : (y)

#define Max(x, y)   (x) < (y) ? (y) : (x)

#define E(x)        (1 << (x))

#define iabs(x)     (x) < 0 ? -(x) : (x)

#define OUT(x)  printf("%I64d\n", x)

#define lowbit(x)   (x)&(-x)

#define Read()  freopen("din.txt", "r", stdin)

#define Write() freopen("dout.txt", "w", stdout);





#define Nn 510007

#define Mc 26



using namespace std;



class Acautomaton

{

    private:



    int chd[Nn][Mc];

    int fail[Nn];

    int ID[Mc];

    int val[Nn];

    int Q[Nn];

    int sz;



    public:



    void Init()

    {

        fail[0] = 0;

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

        {

            ID[i] = i;

        }

    }

    void Reset()

    {

        CL(chd[0],0);

        sz = 1;

    }

    void insert(char *s,int key)

    {

        int p = 0;

        for (; *s; s++)

        {

            int k = ID[*s - 'a'];

            if (!chd[p][k])

            {

                CL(chd[sz],0);

                val[sz] = 0;

                chd[p][k] = sz++;

            }

            p = chd[p][k];

        }

        val[p] += key;

    }

    void Build()

    {

        int *s = Q ,*e = Q,i;

        for (i = 0; i < Mc; ++i)

        {

            if (chd[0][i])

            {

                *e++ = chd[0][i];

                fail[chd[0][i]] = 0;

            }

        }

        while (s != e)

        {

            int u = *s++;

            for (i = 0; i < Mc; ++i)

            {

                int &v = chd[u][i];

                if (v)

                {

                    *e++ = v;

                    fail[v] = chd[fail[u]][i];

                }

                else v = chd[fail[u]][i];

            }

        }

    }

    int solve(char *s)

    {

        int p = 0;

        int k,ans = 0;

        for (; *s; s++)

        {

            k = ID[*s - 'a'];

            while (!chd[p][k] && p != 0) p = fail[p];



            p = chd[p][k];



            int rt = p;

            while (rt != 0 && val[rt] != -1)

            {

                ans += val[rt];

                val[rt] = -1;

                rt = fail[rt];

            }

        }

        return ans;

    }

}ac;



char str[57],tr[1000007];

int n;



int main()

{

    int T;

    int i;

    scanf("%d",&T);

    while (T--)

    {

        ac.Reset(); ac.Init();

        scanf("%d",&n);

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

        {

            scanf("%s",str);

            ac.insert(str,1);

        }

        ac.Build();

        scanf("%s",tr);

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

    }

    return 0;

}

 

HDU 2896 病毒侵袭

题意:

之前指针做的链接:http://www.cnblogs.com/E-star/archive/2013/02/19/2917593.html

现在数组模拟的代码:

View Code
#include <iostream>

#include <cstdio>

#include <cmath>

#include <vector>

#include <cstring>

#include <algorithm>

#include <string>

#include <set>

#include <functional>

#include <numeric>

#include <sstream>

#include <stack>

#include <map>

#include <queue>



#define CL(arr, val)    memset(arr, val, sizeof(arr))



#define ll long long

#define inf 0x7f7f7f7f

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)



#define L(x)    (x) << 1

#define R(x)    (x) << 1 | 1

#define MID(l, r)   (l + r) >> 1

#define Min(x, y)   (x) < (y) ? (x) : (y)

#define Max(x, y)   (x) < (y) ? (y) : (x)

#define E(x)        (1 << (x))

#define iabs(x)     (x) < 0 ? -(x) : (x)

#define OUT(x)  printf("%I64d\n", x)

#define lowbit(x)   (x)&(-x)

#define Read()  freopen("din.txt", "r", stdin)

#define Write() freopen("dout.txt", "w", stdout);





#define Nn 100007

#define Mc 95



using namespace std;



set<int>iset;



class Acautomaton

{

    private:



    int chd[Nn][Mc];

    int fail[Nn];

    int val[Nn];

    int ID[Mc];

    int Q[Nn];

    int sz;



    public :



    void Init()

    {

        fail[0] = 0;

    }

    void Reset()

    {

        CL(chd[0],0);

        sz = 1;

    }

    void Insert(char *s,int key)

    {

        int k;

        int p = 0;

        for (; *s; s++)

        {

            k = *s - 32;

//            printf("%d\n",k);

            if (!chd[p][k])

            {

                CL(chd[sz],0);

                val[sz] = 0;

                chd[p][k] = sz++;

            }

            p = chd[p][k];

        }

        val[p] = key;

    }

    void Build()

    {

        int *s = Q, *e = Q;

        int i;

        for (i = 0; i < Mc; ++i)

        {

            if (chd[0][i])

            {

                fail[chd[0][i]] = 0;

                *e++ = chd[0][i];

            }

        }



        while (s != e)

        {

//            printf(">>>\n");

            int u = *s++;

            for (i = 0; i < Mc; ++i)

            {

                int &v = chd[u][i];

                if (v)

                {

                    *e++ = v;

                    fail[v] = chd[fail[u]][i];

                    val[v] |= val[fail[v]];

                }

                else v = chd[fail[u]][i];

            }

        }

    }

    void solve(char *s)

    {

        int k;

        iset.clear();

        int p = 0;

        for (; *s; s++)

        {

            k = *s - 32;

            while (!chd[p][k] && p != 0) p = fail[p];



            p = chd[p][k];

            int rt = p;

            while (rt != 0)

            {

                if (val[rt] != 0)

                {

                    iset.insert(val[rt]);

                }

                rt = fail[rt];

            }

        }

    }



}ac;



int n,m;

char s1[201], s2[10007];



int main()

{

//    printf("%d\n",'z');

//    Read();

    int i;

    set<int>::iterator it;

    while (~scanf("%d",&n))

    {

        ac.Reset(); ac.Init();

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

        {

            scanf("%s",s1);

            ac.Insert(s1,i + 1);

        }



        ac.Build();



        int total = 0;

        scanf("%d",&m);

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

        {

            scanf("%s",s2);

            ac.solve(s2);

            if (iset.size() != 0)

            {

                total++;

                printf("web %d:",i + 1);

                for (it = iset.begin(); it != iset.end(); ++it)

                {

                    printf(" %d",*it);

                }

                printf("\n");

            }

        }

        printf("total: %d\n",total);

    }

    return 0;

}

 

 HDU 3065 病毒侵袭持续中

题意:中文......

思路:

模板题的多模式串匹配,

View Code
#include <iostream>

#include <cstdio>

#include <cmath>

#include <vector>

#include <cstring>

#include <algorithm>

#include <string>

#include <set>

#include <functional>

#include <numeric>

#include <sstream>

#include <stack>

#include <map>

#include <queue>



#define CL(arr, val)    memset(arr, val, sizeof(arr))



#define ll long long

#define inf 0x7f7f7f7f

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)



#define L(x)    (x) << 1

#define R(x)    (x) << 1 | 1

#define MID(l, r)   (l + r) >> 1

#define Min(x, y)   (x) < (y) ? (x) : (y)

#define Max(x, y)   (x) < (y) ? (y) : (x)

#define E(x)        (1 << (x))

#define iabs(x)     (x) < 0 ? -(x) : (x)

#define OUT(x)  printf("%I64d\n", x)

#define lowbit(x)   (x)&(-x)

#define Read()  freopen("din.txt", "r", stdin)

#define Write() freopen("dout.txt", "w", stdout);





#define Nn 500007

#define Mc 95

#define N 1007

using namespace std;





int num[N];

class Acautomaton

{

    private:



    int chd[Nn][Mc];

    int fail[Nn];

    int val[Nn];

    int Q[Nn];

    int sz;



    public:



    void Init()

    {

        CL(chd[0],0);

        fail[0] = 0;

        sz = 1;

    }



    void Insert(char *s,int key)

    {

        int k;

        int p = 0;

        for (; *s; ++s)

        {

            k = *s - 32;

            if (!chd[p][k])

            {

                CL(chd[sz],0);

                val[sz] = 0;

                chd[p][k] = sz++;

            }

            p = chd[p][k];

        }

        val[p] = key;

    }

    void Build()

    {

        int *s = Q, *e = Q;

        int i;

        for (i = 0; i < Mc; ++i)

        {

            if (chd[0][i])

            {

                fail[chd[0][i]] = 0;

                *e++ = chd[0][i];

            }

        }

        while (s != e)

        {

            int u = *s++;

            for (i = 0; i < Mc; ++i)

            {

                int &v = chd[u][i];

                if (v)

                {

                    fail[v] = chd[fail[u]][i];

//                    val[v] |= val[fail[v]];//这里题目说了不用考虑两个病毒特征码可能有相互包含或者有重叠的特征码段。这里加与不加都对

                    *e++ = v;

                }

                else v = chd[fail[u]][i];



            }

        }

    }

    void solve(char *s)

    {

        int k;

        int p = 0;

        for (; *s; ++s)

        {

            k = *s - 32;

            while (!chd[p][k] && p != 0) p = fail[p];

            p = chd[p][k];

            int rt = p;

            while (rt != 0)

            {

                if (val[rt] != 0)

                {

                    num[val[rt]]++;//这里val不能置为-1,如果置为-1就不能统计某一个字符串出现的次数了,只能表示出新过

                }

                rt = fail[rt];

            }

        }

    }

}ac;





char str[N][55];

char tr[2000002];

int n;



int main()

{

//    Read();

    int i;

    while (~scanf("%d",&n))

    {

        CL(num,0);

        ac.Init();

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

        {

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

            ac.Insert(str[i],i + 1);

        }



        ac.Build();



        scanf("%s",tr);

        ac.solve(tr);

//            printf(">>>\n");

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

        {

            if (num[i + 1] != 0)

            {

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

            }

        }

    }

    return 0;

}

 

ZOJ 3430  Detect the Virus

只要翻译之后就是很裸AC自动机匹配了,悲剧的,跳了n就不知道为什么老是sf

无语:

ps:后来改了老长时间还是不对,最后看了一下结题报告,这里最坑爹了。这里翻译后的字母在0-255之间 包括了’\0‘表示字符串的结束,如果我们中间翻译出了'\0'那么后边的字符就没有了,翻译后得到的字符也就不对了,MD查了n久,重写了n次。郁闷啊。。。

View Code
#include <iostream>

#include <cstdio>

#include <cmath>

#include <vector>

#include <cstring>

#include <algorithm>

#include <string>

#include <set>

#include <functional>

#include <numeric>

#include <sstream>

#include <stack>

#include <map>

#include <queue>



#define CL(arr, val)    memset(arr, val, sizeof(arr))



#define ll long long

#define inf 0x7f7f7f7f

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)



#define L(x)    (x) << 1

#define R(x)    (x) << 1 | 1

#define MID(l, r)   (l + r) >> 1

#define Min(x, y)   (x) < (y) ? (x) : (y)

#define Max(x, y)   (x) < (y) ? (y) : (x)

#define E(x)        (1 << (x))

#define iabs(x)     (x) < 0 ? -(x) : (x)

#define OUT(x)  printf("%I64d\n", x)

#define lowbit(x)   (x)&(-x)

#define Read()  freopen("din.txt", "r", stdin)

#define Write() freopen("dout.txt", "w", stdout);





#define Nn 33000

#define Mc 257



using namespace std;



int a[Nn];

char s1[Nn];

int ts[Nn];

int tl,la;

bool vt[Nn];

int n,m;

int cal[Nn];

int ctk[256];



class Ac

{

    private:



    int chd[Nn][Mc];

    int fail[Nn];

    int val[Nn];

//    int num[Nn];

    int Q[Nn];

    int sz;



    public:



    void Init()

    {

        CL(chd[0],0);

        fail[0] = 0;

        sz = 0;

//        CL(num,0);

    }

    void Insert(int *s,int len,int key)

    {

        int k,p = 0,i;

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

        {

            k = s[i];

            if (!chd[p][k])

            {

                chd[p][k] = ++sz;

                CL(chd[sz],0);

                val[sz] = 0;

                cal[sz] = 0;

            }

            p = chd[p][k];

        }

        val[p] = key;

//        num[key]++;

    }

    void Build()

    {

        int i;

        int *s = Q, *e = Q;

        for (i = 0; i < Mc; ++i)

        {

            if (chd[0][i])

            {

                fail[chd[0][i]] = 0;

                *e++ = chd[0][i];

            }

        }

        while (s != e)

        {

            int u = *s++;

            for (i = 0; i < Mc; ++i)

            {

                int &v = chd[u][i];

                if (v)

                {

                    fail[v] = chd[fail[u]][i];

                    *e++ = v;

                }

                else v = chd[fail[u]][i];

            }

        }

    }

    int Solve(int *s,int len,int key)

    {

        int ans = 0;

        int p = 0,k,i;

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

        {

            k = s[i];

            while (!chd[p][k] && p != 0) p = fail[p];

            p = chd[p][k];



            int rt = p;

            while (rt != 0)

            {

                if (val[rt] > 0 && !vt[val[rt]])

                {

                    vt[val[rt]] = true;

                    ans++;

                }

                rt = fail[rt];

            }

        }

        return ans;

    }

}ac;



vector<int>ivc;

vector<int>::iterator it;



int getNum(char ch)

{

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

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

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

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

    return 63;

}

//这里的ts记录翻译后的字符串,切记要用Int型存储

void change(char *s)

{

    int i,j;

    int len = strlen(s);

    la = 0;

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

    {

         if (s[i] != '=')

         {

             int no = getNum(s[i]);

             ivc.clear();

             while (no)

             {

                 ivc.push_back(no%2);

                 no/=2;

             }

             for (j = ivc.size(); j < 6; ++j) ivc.push_back(0);

             reverse(ivc.begin(),ivc.end());

             for (it = ivc.begin(); it != ivc.end(); ++it) a[la++] = *it;

         }

    }

    la -= (la%8);

    tl = 0; CL(ts,0);

    int no = 0;

    for (i = 0; i < la; ++i)

    {

        no = (no<<1) + a[i];

        if (i%8 == 7)

        {

            ts[tl++] = no;

            no = 0;

        }

    }

    //无敌的未操作翻译。。。

//    tl = 0; CL(ts,0);

//    int len = 0,x = 0;

//    for (i = 0; s[i] != '=' && s[i]; ++i)

//    {

//        len += 6;

//        x = (x<<6)|getNum(s[i]);

//        if (len >= 8)

//        {

//            ts[tl++] = ((x>>(len - 8))&0xff);

//            len -= 8;

//        }

//    }

}

int main()

{

//    printf("%d\n",'\0');

//    Read();

    int i;



    while (~scanf("%d",&n))

    {

        ac.Init();

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

        {

            scanf("%s",s1);

            change(s1);



            ac.Insert(ts,tl,i + 1);

        }

        ac.Build();

        scanf("%d",&m);

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

        {

            scanf("%s",s1);

            change(s1);



            CL(vt,false);

            printf("%d\n",ac.Solve(ts,tl,i + 1));

        }

        printf("\n");

    }

    return 0;

}

 

 

 AC自动机+矩阵

 

pku 2778 DNA Sequence

题意:

给定n个病毒DNA串,求一个长度为m的DNA片段不包含任何一个病毒串的的可能数?

思路:
首先根据n个DNA串构造AC自动机,然后根据AC自动机构造矩阵,然后转化到Matrix大神的是个利用举证解决的问题的例八中去。

才开始我一直以为推出的举证和斐波那契数列的意思一样,转了个死弯,这里是把AC自动机这个图转化为邻接矩阵,然后求从一个状态到另一个状态经过m条边的的可能数。这个通过AC自动机得到的矩阵其实就是一个关系矩阵。

这里借鉴了一下胡浩大神的AC自动机模板:

 

View Code
#include <iostream>

#include <cstdio>

#include <cmath>

#include <vector>

#include <cstring>

#include <algorithm>

#include <string>

#include <set>

#include <functional>

#include <numeric>

#include <sstream>

#include <stack>

#include <map>

#include <queue>



#define CL(arr, val)    memset(arr, val, sizeof(arr))



#define ll long long

#define inf 0x7f7f7f7f

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)



#define L(x)    (x) << 1

#define R(x)    (x) << 1 | 1

#define MID(l, r)   (l + r) >> 1

#define Min(x, y)   (x) < (y) ? (x) : (y)

#define Max(x, y)   (x) < (y) ? (y) : (x)

#define E(x)        (1 << (x))

#define iabs(x)     (x) < 0 ? -(x) : (x)

#define OUT(x)  printf("%I64d\n", x)

#define lowbit(x)   (x)&(-x)

#define Read()  freopen("din.txt", "r", stdin)

#define Write() freopen("dout.txt", "w", stdout);





#define Nn 104

#define Mn 4



using namespace std;



int n,m;

int sz;

char s[12];



class Mat

{

    public:

    ll mat[Nn][Nn];

    void init()

    {

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

        {

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

            {

                mat[i][j] = 0;

            }

        }

    }

    void instal()

    {

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

        {

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

            {

                mat[i][j] = (i == j);

            }

        }

    }

}a;

Mat operator*(Mat a,Mat b)

{

    Mat c;  c.init();



    int i,j,k;

    for (k = 0; k <= sz; ++k)

    {

        for (i = 0; i <= sz; ++i)

        {

            for (j = 0; j <= sz; ++j)

            {

                if (!a.mat[i][k] || !b.mat[k][j]) continue;

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

                if (c.mat[i][j] >= 100000) c.mat[i][j] %= 100000;

            }

        }

    }

    return c;

}

Mat operator^(Mat a,int k)

{

    Mat c; c.instal();



    while (k)

    {

        if (k&1) c = c*a;

        k >>= 1;

        a = a*a;

    }

    return c;

}



class AC

{

    public:



    int chd[Nn][Mn];

    int fail[Nn];

    int val[Nn];

    int Q[Nn];



    void Init()

    {

        CL(chd[0],0);

        fail[0] = 0;

        sz = 0;

    }

    int getR(char ch)

    {

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

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

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

        return 3;

    }

    void Insert(char *s,int key)

    {

        int p = 0;

        int k;

        for (; *s; ++s)

        {

            k = getR(*s);

            if (!chd[p][k])

            {

                chd[p][k] = ++sz;

                val[sz] = 0;

                CL(chd[sz],0);

            }

            p = chd[p][k];

        }

        val[p] = key;

    }

    void Build()

    {

        int i;

        int *s = Q,*e = Q;

        for (i = 0; i < Mn; ++i)

        {

            if (chd[0][i])

            {

                fail[chd[0][i]] = 0;

                *e++ = chd[0][i];

            }

        }

        while (s != e)

        {

            int u = *s++;

            for (i = 0; i < Mn; ++i)

            {

                int &v = chd[u][i];

                if (v)

                {

                    fail[v] = chd[fail[u]][i];

                    val[v] |= val[fail[v]];//这里的病毒可能存在包含关系

                    *e++ = v;

                }

                else v = chd[fail[u]][i];

            }

        }

    }

    int Solve()

    {

        int i,j;

        ll ans = 0;

        a.init();

        for (i = 0; i <= sz; ++i)

        {

            if (val[i]) continue;

            for (j = 0; j < Mn; ++j)

            {

                if(val[chd[i][j]]) continue;

                a.mat[i][chd[i][j]]++;

            }

        }

        a = a^m;

        for (i = 0; i <= sz; ++i)

        {

            if (val[i] != 0) continue;

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

            if (ans >= 100000) ans %= 100000;

        }

        return ans;

    }

}ac;



int main()

{

//    Read();

    int i;

    ac.Init();

    scanf("%d%d",&n,&m);

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

    {

        scanf("%s",s);

        ac.Insert(s,1);

    }

    ac.Build();

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

    return 0;

}

 

 HDU2243  考研路茫茫——单词情结

题意:中文..

思路:

首先看到的是至少包含一个词根,所以我们想到他的对立面,我们求出26^1 + 26^2 + ...... + 26^L 所有的可能的串,然后减去一个也不包含病毒串的数量,就求出了结果。

这里求要求模2^64 long long 是不能存下的怎么办?我们直接用unsigned long long 来表示他表示的最大值为2^64 - 1如果超过此值,他会直接回到0加起就相当于%2^64了。然后求和时有一个二分的方法求和a^1 + a^2 + ...... + a^k  -》sum(a,k) 如果k是偶数: => sum(a,k/2) * (a^(k/2) + 1)   如果为奇数得:sum(a,k -1) + a^k 时间复杂度是log(L)然后利用AC自动机构造状态图,构造举证,转化为例8 求一个病毒串都不包含的情况,总数减去该数即可。

View Code
#pragma comment(linker, "/STACK:1024000000,1024000000")

#include <iostream>

#include <cstdio>

#include <cmath>

#include <vector>

#include <cstring>

#include <algorithm>

#include <string>

#include <set>

#include <functional>

#include <numeric>

#include <sstream>

#include <stack>

#include <map>

#include <queue>



#define CL(arr, val)    memset(arr, val, sizeof(arr))



#define ll unsigned __int64

#define inf 0x7f7f7f7f

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)



#define L(x)    (x) << 1

#define R(x)    (x) << 1 | 1

#define MID(l, r)   (l + r) >> 1

#define Min(x, y)   (x) < (y) ? (x) : (y)

#define Max(x, y)   (x) < (y) ? (y) : (x)

#define E(x)        (1 << (x))

#define iabs(x)     (x) < 0 ? -(x) : (x)

#define OUT(x)  printf("%I64d\n", x)

#define lowbit(x)   (x)&(-x)

#define Read()  freopen("din.txt", "r", stdin)

#define Write() freopen("dout.txt", "w", stdout);





#define Nn 26

#define Mn 26



using namespace std;



int n;

int sz;

__int64 L;

char s[7];



class Mat

{

    public :



    ll mat[Nn][Nn];

    int i,j;

    void e()

    {

        for (i = 0; i <= sz; ++i)

        {

            for (j = 0; j <= sz; ++j)

            {

                mat[i][j] = (i == j);

            }

        }

    }

    void init()

    {

        for (i = 0; i <= sz; ++i)

        {

            for (j = 0; j <= sz; ++j)

            {

                mat[i][j] = 0;

            }

        }

    }

}I;

Mat operator*(Mat a,Mat b)

{

    Mat c; c.init();

    int i,j,k;

    for (k = 0; k <= sz; ++k)

    {

        for (i = 0; i <= sz; ++i)

        {

            for (j = 0; j <= sz; ++j)

            {

                if (!a.mat[i][k] && !b.mat[k][j]) continue;

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

            }

        }

    }

    return c;

}

Mat operator^(Mat a,ll k)

{

    Mat c; c.e();



    while (k)

    {

        if (k&1) c = c*a;

        k >>= 1;

        a = a*a;

    }

    return c;

}

Mat operator+ (Mat a,Mat b)

{

    Mat c; c.init();

    int i,j;

    for (i = 0; i <= sz; ++i)

    {

        for (j = 0; j <= sz; ++j)

        {

            c.mat[i][j] = a.mat[i][j] + b.mat[i][j];

        }

    }

    return c;

}

Mat matSum(Mat a,__int64 k)

{

    if (k == 1LL) return a;

    if (k&1LL) return (a^k) + matSum(a,k - 1);

    else return matSum(a,k/2) * ((a^(k/2)) + I);

//    if(k==1LL) return a;

//    if(k&1LL) return (a^k)+matSum(a,k-1);

//    else return matSum(a,k/2) * ((a^(k/2))+I);//I为单位矩阵

}



ll modmul(ll a,ll b)

{

    ll res = 0;

    ll tmp = a;

    while (b)

    {

        if (b&1) res = (res + tmp);

        tmp = (tmp+tmp);

        b>>=1;

    }

    return res;

}

ll modexp(ll a,ll b)

{

    ll res = 1;

    ll tmp = a;

    while (b)

    {

        if (b&1) res = modmul(res,tmp);

        tmp = modmul(tmp,tmp);

        b>>=1;

    }

    return res;

}

ll numSum(ll a,ll k)

{

    if (k == 1ll) return a;

    if (k&(1ll)) return numSum(a,k - 1) + modexp(a,k);

    else return numSum(a,k/2) * (modexp(a,k/2) + 1);

}



class AC

{

    public :



    int chd[Nn][Mn];

    int fail[Nn];

    int val[Nn];

    int Q[Nn];





    void Init()

    {

        CL(chd[0],0);

        fail[0] = 0;

        sz = 0;

    }

    void Insert(char *s,int key)

    {

        int k, p = 0;

        for (; *s; s++)

        {

            k = *s - 'a';

            if (!chd[p][k])

            {

                chd[p][k] = ++sz;

                CL(chd[sz],0);

                val[sz] = 0;

            }

            p = chd[p][k];

        }

        val[p] = key;

    }

    void Build()

    {

        int *s = Q, *e = Q;

        int i;

        for (i = 0; i < Mn; ++i)

        {

            if (chd[0][i])

            {

                fail[chd[0][i]] = 0;

                *e++ = chd[0][i];

            }

        }

        while (s != e)

        {

            int u = *s++;

            for (i = 0; i < Mn; ++i)

            {

                int &v = chd[u][i];

                if (v)

                {

                    fail[v] = chd[fail[u]][i];

                    val[v] |= val[fail[v]];

                    *e++ = v;

                }

                else v = chd[fail[u]][i];

            }

        }

    }

    void Solve()

    {

        int i,j;

        Mat a;

        a.init();



        for (i = 0; i <= sz; ++i)

        {

            if (val[i]) continue;

            for (j = 0; j < Mn; ++j)

            {

                if (val[chd[i][j]]) continue;

                a.mat[i][chd[i][j]]++;

            }

        }



        Mat res = matSum(a,L);

        ll s = numSum(26,L);







        ll sum = 0;

        for (i = 0; i <= sz; ++i)

        {

            if (val[i]) continue;

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

        }

//        printf("%I64d %I64d\n",s,sum);

        printf("%I64u\n",(s - sum));//这里一定要用%I64u否则你会很惨。。

    }

}ac;



int main()

{

//    Read();

    int i;



    while (~scanf("%d%I64d",&n,&L))

    {

        ac.Init();

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

        {

            scanf("%s",s);

            ac.Insert(s,1);

        }

        ac.Build();

        I.e();

        ac.Solve();

    }

    return 0;

}

 

 AC自动机+DP

pku 3691 DNA repair

 or HDU 2457

指针解答:http://www.cnblogs.com/E-star/archive/2013/02/20/2919301.html

数组模拟模板:

View Code
#include <iostream>

#include <cstdio>

#include <cmath>

#include <vector>

#include <cstring>

#include <algorithm>

#include <string>

#include <set>

#include <functional>

#include <numeric>

#include <sstream>

#include <stack>

#include <map>

#include <queue>



#define CL(arr, val)    memset(arr, val, sizeof(arr))



#define ll unsigned __int64

#define inf 0x7f7f7f7f

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)



#define L(x)    (x) << 1

#define R(x)    (x) << 1 | 1

#define MID(l, r)   (l + r) >> 1

#define Min(x, y)   (x) < (y) ? (x) : (y)

#define Max(x, y)   (x) < (y) ? (y) : (x)

#define E(x)        (1 << (x))

#define iabs(x)     (x) < 0 ? -(x) : (x)

#define OUT(x)  printf("%I64d\n", x)

#define lowbit(x)   (x)&(-x)

#define Read()  freopen("din.txt", "r", stdin)

#define Write() freopen("dout.txt", "w", stdout);





#define Nn 1007

#define Mn 4



using namespace std;



char s1[22],s2[Nn];

int n;



class AC

{

    public :



    int chd[Nn][Mn];

    int fail[Nn];

    int val[Nn];

    int Q[Nn];

    int dp[Nn][Nn];

    int sz;





    void Init()

    {

        CL(chd[0],0);

        fail[0] = 0;

        val[0] = 0;

        sz = 0;

    }

    int getR(char ch)

    {

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

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

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

        return 3;

    }

    void Insert(char *s,int key)

    {

        int k, p = 0;

        for (; *s; s++)

        {

            k = getR(*s);

            if (!chd[p][k])

            {

                chd[p][k] = ++sz;

                CL(chd[sz],0);

                val[sz] = 0;

            }

            p = chd[p][k];

        }

        val[p] = key;

    }

    void Build()

    {

        int *s = Q, *e = Q;

        int i;

        for (i = 0; i < Mn; ++i)

        {

            if (chd[0][i])

            {

                fail[chd[0][i]] = 0;

                *e++ = chd[0][i];

            }

        }

        while (s != e)

        {

            int u = *s++;

            for (i = 0; i < Mn; ++i)

            {

                int &v = chd[u][i];

                if (v)

                {

                    fail[v] = chd[fail[u]][i];

                    val[v] |= val[fail[v]];

                    *e++ = v;

                }

                else v = chd[fail[u]][i];

            }

        }

    }

    int Solve()

    {

        int i,j,k;

        int len = strlen(s2);

//        printf("%s %d\n",s2,len);

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

        {

            for (j = 0; j <= sz; ++j)

            {

                dp[i][j] = inf;

            }

        }

        dp[0][0] = 0;

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

        {

            for (j = 0; j <= sz; ++j)

            {

                if (dp[i][j] != inf && val[j] == 0)

                {

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

                    {

                        if (val[chd[j][k]]) continue;

                        int add = (k != getR(s2[i]));

                        dp[i + 1][chd[j][k]] = min(dp[i + 1][chd[j][k]],dp[i][j] + add);

                    }

                }

            }

        }



        int ans = -1;

        for (i = 0; i <= sz; ++i)

        {

//            printf("%d\n",dp[len][i]);



            if (dp[len][i] != inf && (ans == -1 || ans > dp[len][i])) ans = dp[len][i];

        }

        return ans;

    }

}ac;



int main()

{

//    Read();

    int i;

    int cas = 1;

    while (~scanf("%d",&n))

    {

        if (!n) break;

        ac.Init();

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

        {

            scanf("%s",s1);

            ac.Insert(s1,1);

        }

        ac.Build();

        scanf("%s",s2);

        printf("Case %d: %d\n",cas++,ac.Solve());

    }

    return 0;

}

 

 HDU 2825 Wireless Password

 题意:

给定M个字符串,然后给出密码的长度为n ,字符串都是用小写字母组成的,求可能组成的密码,密码必须满足至少包含k个给出的字符串。

思路:

AC自动机那部分就不用说了,模板。关键是DP部分,dp[i +1][chd[j][l]][k|val[chd[j][l]]] += dp[i][j][k];   i 表示当前枚举的字符串的长度, j表示状态,k表示包含了几个给定串。这里的每个状态对应了2^10个可能。我们只要枚举经过i个字符串能够达到该状态的个数即可。

View Code
#include <iostream>

#include <cstdio>

#include <cmath>

#include <vector>

#include <cstring>

#include <algorithm>

#include <string>

#include <set>

#include <functional>

#include <numeric>

#include <sstream>

#include <stack>

#include <map>

#include <queue>



#define CL(arr, val)    memset(arr, val, sizeof(arr))



#define ll unsigned __int64

#define inf 0x7f7f7f7f

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)



#define L(x)    (x) << 1

#define R(x)    (x) << 1 | 1

#define MID(l, r)   (l + r) >> 1

#define Min(x, y)   (x) < (y) ? (x) : (y)

#define Max(x, y)   (x) < (y) ? (y) : (x)

#define E(x)        (1 << (x))

#define iabs(x)     (x) < 0 ? -(x) : (x)

#define OUT(x)  printf("%I64d\n", x)

#define lowbit(x)   (x)&(-x)

#define Read()  freopen("din.txt", "r", stdin)

#define Write() freopen("dout.txt", "w", stdout);





#define Nn 107

#define Mn 26



using namespace std;



const int mod = 20090717;

char s1[12];

int n,M,K;



class AC

{

    public :



    int chd[Nn][Mn];

    int fail[Nn];

    int val[Nn];

    int Q[Nn];

    int dp[26][Nn][(1<<10)];

    int sz;





    void Init()

    {

        CL(chd[0],0);

        fail[0] = 0;

        sz = 0;

    }



    void Insert(char *s,int key)

    {

        int k, p = 0;

        for (; *s; s++)

        {

            k = *s - 'a';

            if (!chd[p][k])

            {

                chd[p][k] = ++sz;

                CL(chd[sz],0);

                val[sz] = 0;

            }

            p = chd[p][k];

        }

        val[p] = (1<<key);

    }

    void Build()

    {

        int *s = Q, *e = Q;

        int i;

        for (i = 0; i < Mn; ++i)

        {

            if (chd[0][i])

            {

                fail[chd[0][i]] = 0;

                *e++ = chd[0][i];

            }

        }

        while (s != e)

        {

            int u = *s++;

            for (i = 0; i < Mn; ++i)

            {

                int &v = chd[u][i];

                if (v)

                {

                    fail[v] = chd[fail[u]][i];

                    val[v] |= val[fail[v]];

                    *e++ = v;

                }

                else v = chd[fail[u]][i];

            }

        }

    }

    int getR(int x)

    {

        int res = 0;

        while (x)

        {

            if (x&1) res++;

            x = (x>>1);

        }

        return res;

    }

    void Solve()

    {

        int i,j,k,l;

        CL(dp,0);



        dp[0][0][0] = 1;

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

        {

            for (j = 0; j <= sz; ++j)

            {

                for (k = 0; k < (1<<M); ++k)

                {

                    if (dp[i][j][k])

                    {

                        for (l = 0; l < Mn; ++l)

                        {

                            int msk = k|val[chd[j][l]];

                            dp[i + 1][chd[j][l]][msk] += dp[i][j][k];

                            if (dp[i + 1][chd[j][l]][msk] >= mod)

                            dp[i + 1][chd[j][l]][msk] -= mod;

                        }

                    }

                }

            }

        }

        int ans = 0;

        for (i = 0; i <= sz; ++i)

        {

            for (j = 0; j < (1<<M); ++j)

            {

                int s = getR(j);

                if (s >= K)

                {

                    ans += dp[n][i][j];

                    if (ans >= mod) ans -= mod;

                }

            }

        }

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

    }

}ac;



int main()

{

//    Read();

    int i;

    while (~scanf("%d%d%d",&n,&M,&K))

    {

        if (!n && !M && !K) break;

        ac.Init();

        for (i = 0; i < M; ++i)

        {

            scanf("%s",s1);

            ac.Insert(s1,i);

        }

        ac.Build();

        ac.Solve();

    }

    return 0;

}

 

 pku 1625 Censored!

题意:

给定n个可选字符,求组成长度为m的字符串不包含给定的p个病毒串的可能数。(出现的字符都是由n个给定字符组成)。

思路:

这在AC自动机DP里面算是简单的得了,不过这里涉及的大整数,所以显得有些复杂呢,这里直接用java的大整数写也就比较简单了。

dp[i][j] += dp[k][j -1]    i表示状态j表示组成字符串的长度  k是i的父亲状态、

View Code
mport java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.math.BigInteger;

import java.util.Arrays;

import java.util.Scanner;



public class Main {



    /**

     * @param args

     */



    public int n, m, p;



    public int chd[][] = new int[107][55];

    public int fail[] = new int[107];

    public int val[] = new int[107];

    public int Q[] = new int[107];

    public int ID[] = new int[256];

    public int sz;

    String DIC;

    public BigInteger dp[][] = new BigInteger[107][55];

    int Mn;



    public void Init() {

        Arrays.fill(chd[0], 0);

        fail[0] = 0;

        sz = 0;

        for (int i = 0; i < DIC.length(); ++i) {

            ID[DIC.charAt(i)] = i;

        }

        Mn = DIC.length();

    }



    public void Insert(String s, int key) {

        int p = 0;

        int i;

        for (i = 0; i < s.length(); ++i) {

            int k = ID[s.charAt(i)];

            if (chd[p][k] == 0) {

                chd[p][k] = ++sz;

                Arrays.fill(chd[sz], 0);

                val[sz] = 0;

            }

            p = chd[p][k];

        }

        val[p] = key;

    }



    public void Build() {

        int fr = 0, tl = 0, i;

        for (i = 0; i < Mn; ++i) {

            if (chd[0][i] != 0) {

                Q[tl++] = chd[0][i];

                fail[chd[0][i]] = 0;

            }

        }

        while (fr != tl) {

            int u = Q[fr++];

            for (i = 0; i < Mn; ++i) {

                int v = chd[u][i];

                if (v != 0) {

                    Q[tl++] = v;

                    fail[v] = chd[fail[u]][i];

                    val[v] |= val[fail[v]];

                } else {

                    chd[u][i] = chd[fail[u]][i];

                }

            }

        }

    }



    public void Solve() {

        int i, j, k;

        // Scanner cin = new Scanner(System.in);

        

        try {

            BufferedReader cin = new BufferedReader(new InputStreamReader(System.in, "ISO-8859-1"));



            String a[];

            a = cin.readLine().split(" ");

            n = Integer.parseInt(a[0]);

            m = Integer.parseInt(a[1]);

            p = Integer.parseInt(a[2]);



            DIC = cin.readLine();

//            System.out.println(n + " " + m + " " + p + " " + DIC);

            this.Init();



            for (i = 0; i < p; ++i) {

                String tmp = cin.readLine();

                this.Insert(tmp, 1);

            }

            this.Build();



            for (j = 0; j <= m; j++) {

                for (i = 0; i <= sz; i++) {

                    dp[i][j] = BigInteger.ZERO;

                }

            }



            dp[0][0] = BigInteger.ONE;

            for (j = 0; j < m; ++j) {

                for (i = 0; i <= sz; ++i) {

                    if (val[i] != 0)

                        continue;

                    for (k = 0; k < Mn; ++k) {

                        if (val[chd[i][k]] != 0)

                            continue;

                        dp[chd[i][k]][j + 1] = dp[chd[i][k]][j + 1]

                                .add(dp[i][j]);

                    }

                }

            }

            BigInteger ans = BigInteger.ZERO;

            for (i = 0; i <= sz; ++i) {

                if (val[i] != 0)

                    continue;

                ans = ans.add(dp[i][m]);

            }

            System.out.println(ans);



        } catch (IOException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

    }



    public static void main(String[] args) {

        // TODO Auto-generated method stub



        Main res = new Main();

        res.Solve();

    }



}

 

HDU 4534 郑厂长系列故事——新闻净化

题意:中文..

思路:
一看就是AC自动机+D的题目,可是还是太弱看不出来。dp[i][j][k]表示但我们面临一个字符时的状态  i表示处理了i个字符,j表示树上的一个状态,k表示所必须包含的字符串包含了多好啊个。才开始我以为直接k表示包含了多少个不就行了吗,可是如果存在两个形同的串的值为999那么就会出错,所以我们用状态压缩来表示必须包含的串有多好个,还有这里会存在串包含串的情况,所以要在构造时处理,否则会出错的。

View Code
//#pragma comment(linker,"/STACK:327680000,327680000")

#include <iostream>

#include <cstdio>

#include <cmath>

#include <vector>

#include <cstring>

#include <algorithm>

#include <string>

#include <set>

#include <functional>

#include <numeric>

#include <sstream>

#include <stack>

#include <map>

#include <queue>



#define CL(arr, val)    memset(arr, val, sizeof(arr))



#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1



#define ll __int64

#define L(x)    (x) << 1

#define R(x)    (x) << 1 | 1

#define MID(l, r)   (l + r) >> 1

#define Min(x, y)   (x) < (y) ? (x) : (y)

#define Max(x, y)   (x) < (y) ? (y) : (x)

#define E(x)        (1 << (x))

#define iabs(x)     (x) < 0 ? -(x) : (x)

#define OUT(x)  printf("%I64d\n", x)

#define lowbit(x)   (x)&(-x)

#define Read()  freopen("din.txt", "r", stdin)

#define Write() freopen("dout.txt", "w", stdout);





#define M 26

#define N 107

#define ST 1617



using namespace std;





const int inf = 0x1F1F1F1F;

const int mod = 1000000007;



int dp[2][ST][1<<8],rs[2][ST][1<<8];



int X,cas;



class AC

{

    public :



    int chd[ST][M];

    int fail[ST];

    int val[ST];//每个串对应的值

    int type[ST];//表示该串包含了多少必须的字符串

    int nok[ST];//是否是非法的

    int Q[ST];

    int sz;



    void Init()

    {

        CL(chd[0],0);

        CL(type,0);

        CL(nok,0);

        fail[0] = 0;

        val[0] = 0;

        sz = 0;

    }

    void Insert(char *s,int key)

    {

        int p = 0;

        for (; *s; s++)

        {

            int k = *s - 'a';

            if (!chd[p][k])

            {

                chd[p][k] = ++sz;

                val[sz] = 0;

                CL(chd[sz],0);

            }

            p = chd[p][k];

        }

        //这里处理时关键

        if (key == 999)

        {

            type[p] |= (1<<X); X++;

        }

        else if (key == -999)

        {

            nok[p] = 1;

        }

        else

        {

            val[p] += key;

        }

    }

    void Build()

    {

        int i;

        int *s = Q, *e = Q;

        for (i = 0; i < M; ++i)

        {

            if (chd[0][i])

            {

                fail[chd[0][i]] = 0;

                *e++ = chd[0][i];

            }

        }

        while (s != e)

        {

            int u = *s++;

            for (i = 0; i < M; ++i)

            {

                int &v = chd[u][i];

                if (v)

                {

                    fail[v] = chd[fail[u]][i];

                    //同样下边的处理相当重要

                    type[v] |= type[fail[v]];

                    nok[v] |= nok[fail[v]];

                    val[v] += val[fail[v]];

                    *e++ = v;

                }

                else v = chd[fail[u]][i];

            }

        }

    }

    void Solve(char *s)

    {

        int i,j,k;

        int len = strlen(s);

        int u = 0,v = 1;



        for (i = 0; i <= sz; ++i)

        {

            for (j = 0; j < (1<<X); ++j)

            {

                dp[u][i][j] = inf;

                rs[u][i][j] = 0;

            }

        }

        dp[u][0][0] = 0;



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

        {

            for (j = 0; j <= sz; ++j)

            {

                for (k = 0; k < (1<<X); ++k)

                {

                    dp[v][j][k] = inf;

                    rs[v][j][k] = 0;

                }

            }



            for (j = 0; j <= sz; ++j)

            {

                for (k = 0; k < (1<<X); ++k)

                {

                    if (dp[u][j][k] == inf) continue;



                    if (dp[v][j][k] > dp[u][j][k] + 1)

                    {

                        dp[v][j][k] = dp[u][j][k] + 1;

                        rs[v][j][k] = rs[u][j][k];

                    }

                    else if (dp[v][j][k] == dp[u][j][k] + 1 && rs[v][j][k] < rs[u][j][k])

                    {

                        rs[v][j][k] = rs[u][j][k];

                    }



                    int nxt = s[i] - 'a';

                    int msk = chd[j][nxt];

                    int vi = val[msk];

                    int no = nok[msk];



                    if (no == 1) continue;





                   int c = k|type[msk];



                   if (dp[v][msk][c] > dp[u][j][k])

                   {

                       dp[v][msk][c] = dp[u][j][k];

                       rs[v][msk][c] = rs[u][j][k] + vi;

                   }

                   else if (dp[v][msk][c] == dp[u][j][k] && rs[v][msk][c] < rs[u][j][k] + vi)

                   {

                        rs[v][msk][c] = rs[u][j][k] + vi;

                   }

                }

            }

            swap(u,v);

        }

        int res1 = inf,res2 = 0;

        int msk = (1<<X) - 1;

        for (j = 0; j <= sz; ++j)

        {

            if (res1 > dp[u][j][msk])

            {

                res1 = dp[u][j][msk];

                res2 = rs[u][j][msk];

            }

            else if (res1 == dp[u][j][msk] && res2 < rs[u][j][msk])

            {

                res2 = rs[u][j][msk];

            }

        }

        if (res1 == inf)

        {

            printf("Case %d: Banned\n",cas++);

        }

        else

        {

            printf("Case %d: %d %d\n",cas++,res1,res2);

        }

    }

}ac;



char str[19],sa[107];



int main()

{

//    Read();

    int i;

    int n,T;

    cas = 1;

    scanf("%d",&T);

    while (T--)

    {

        scanf("%d",&n);

        ac.Init();

        X = 0; int x;

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

        {

            scanf("%s%d",str,&x);

            ac.Insert(str,x);

        }

        ac.Build();

        scanf("%s",sa);

        ac.Solve(sa);

    }

    return 0;

}

 

 

 

 

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