【Ac自動機+矩陣加速】poj 2778 DNA Sequence

CN_swords發表於2017-08-09

Link:http://poj.org/problem?id=2778

字典樹的每個節點作為一個狀態,矩陣記錄i點走一步的可行的狀態轉移的方法數,用矩陣快速冪計算所有可行的方法數。

//#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long LL;

const int mod = 100000;
const int N = 15;
const int M = 4;
const int root = 0;
//char to[5] = {"ACTG"};
int change(char c){
    if(c == 'A')
        return 0;
    if(c == 'C')
        return 1;
    if(c == 'T')
        return 2;
    if(c == 'G')
        return 3;
}

struct Ma{
    LL p[N*N][N*N];
    int Size;
    void init(int _n){
        Size = _n;
        for(int i = 0; i < Size; i++)
            for(int j = 0; j < Size; j++)
                p[i][j] = 0;
    }
};
struct Aho
{
    struct Node{
        int nex[M];
        int fail,endd;
    }node[N*N];
    int Size;
    queue<int> que;

    int newnode(){
        for(int i = 0; i < M; i++)
            node[Size].nex[i] = 0;
        node[Size].fail = node[Size].endd = 0;
        return Size++;
    }

    void init(){
        while(que.size())   que.pop();
        Size = root;
        newnode();
    }

    void Insert(char *s)
    {
        int L = strlen(s);
        int now = root;
        for(int i = 0; i < L; i++){
            int x = change(s[i]);
            if(node[now].nex[x]==0)
                node[now].nex[x]=newnode();
            now = node[now].nex[x];
        }
        node[now].endd = 1;
    }

    void build()
    {
        node[root].fail = root;
        for(int i = 0; i < M; i++)
        {
            if(node[root].nex[i])
            {
                node[node[root].nex[i]].fail = root;
                que.push(node[root].nex[i]);
            }
        }
        while(que.size())
        {
            int u = que.front();
            if(node[node[u].fail].endd) //當u的字尾是病毒,u也不能出現.
                node[u].endd = 1;
            que.pop();
            for(int i = 0; i < M; i++)
            {
                if(node[u].nex[i]==0)
                    node[u].nex[i] = node[node[u].fail].nex[i];
                else
                {
                    node[node[u].nex[i]].fail = node[node[u].fail].nex[i];
                    que.push(node[u].nex[i]);
                }
            }
        }

//        for(int i = 0; i < Size; i++)
//            printf("[%d %d %d]\n",i,node[i].fail,node[i].endd);
    }

    Ma getMa()
    {
        Ma mat;
        mat.init(Size);
        for(int i = root; i < Size; i++){
            for(int j = 0; j < M; j++){
                if(!node[i].endd && !node[node[i].nex[j]].endd)
                    mat.p[i][node[i].nex[j]] ++;
            }
        }
        return mat;
    }
}aho;

Ma Ma_mult(Ma a,Ma b)
{
    Ma c;
    c.init(a.Size);
    for(int i = 0; i < a.Size; i++){
        for(int j = 0; j < a.Size; j++){
            for(int k = 0; k < a.Size; k++)
                c.p[i][j] += a.p[i][k]*b.p[k][j];
            c.p[i][j] %= mod;
        }
    }
    return c;
}

Ma quick_mi(Ma a,int n)
{
    Ma c;
    c.init(a.Size);
    for(int i = 0; i < c.Size; i++)
        c.p[i][i] = 1;
    while(n)
    {
        if(n&1) c = Ma_mult(c,a);
        a = Ma_mult(a,a);
        n >>= 1;
    }
    return c;
}


char s[N];
int main()
{
    int m,n;
    while(~scanf("%d %d",&m,&n))
    {
        aho.init();
        for(int i = 0; i < m; i++)
        {
            scanf("%s",s);
            aho.Insert(s);
        }
        aho.build();

        Ma mat = aho.getMa();
//        for(int i = 0; i < mat.Size; i++)
//        {
//            for(int j = 0; j < mat.Size; j++)
//                printf("%lld ",mat.p[i][j]);
//            puts("");
//        }
        mat = quick_mi(mat,n);
        LL ans = 0;
        for(int i = 0; i < mat.Size; i++)
            ans += mat.p[0][i];
        printf("%lld\n",ans%mod);
    }
    return 0;
}


相關文章