1. 程式人生 > >poj2778 DNA Sequence(AC自動機+矩陣快速冪)

poj2778 DNA Sequence(AC自動機+矩陣快速冪)

題意描述:給m字串,這m個字串是帶有病毒的DNA。然後問一個長度為n的字串不帶有任何病毒有多少中可能?所有字串之後ACGT這幾個字串組成

解題思路:AC自動機+矩陣快速冪

前置內容:鄰接矩陣冪的含義:點選開啟連結

分析:首先根據題意先建一個AC自動機,其實AC自動機本身就是一張圖,AC自動機中的每個結點就相當於圖中的頂點,每個轉移A、C、G、T就相當於一條邊;根據鄰接矩陣冪的含義,我們發現求長度為n的字串的個數就相當於從起點在圖中走n步所能到達的所點的方案數的和,而n又很大,我們可以使用矩陣快速冪;但是本題有限制就是不能帶有某些字串,言外之意就是圖中有些節點不能經過,根據AC自動機中的end[i]我們可以將這種情況去掉

程式碼:

#include <cstdio>
#include <cstring>
#include <queue>
#define MOD 100000
typedef long long ll;
using namespace std;
struct Matrix{
    ll m[110][110];
    int L;
    Matrix(int len){
        L=len;
        for(int i=0;i<L;++i)
            for(int j=0;j<L;++j)
                m[i][j]=0;
    }
};
Matrix mat(Matrix a,Matrix b){
    Matrix c(a.L);
    for(int i=0;i<c.L;++i)
        for(int j=0;j<c.L;++j){
            for(int k=0;k<c.L;++k){
                c.m[i][j]+=(a.m[i][k]*b.m[k][j]);
                c.m[i][j]%=MOD;
            }
        }
    return c;
}
Matrix doexpmat(Matrix a,int num){
    Matrix t(a.L);
    for(int i=0;i<t.L;++i)
        t.m[i][i]=1;
    while(num){
        if(num&1) t=mat(a,t);
        num=num>>1;
        a=mat(a,a);
    }
    return t;
}
struct Trie{
    int next1[110][4],fail[110];
    bool end1[110];
    int root,L;
    int newnode(){
        for(int i=0;i<4;++i) next1[L][i]=-1;
        end1[L++]=false;
        return L-1;
    }
    void init(){ L=0; root=newnode(); }
    int getchs(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 insertnode(char* str){
        int now=root;
        int len=strlen(str);
        for(int i=0;i<len;++i){
            int to=getchs(str[i]);
            if(next1[now][to]==-1)
                next1[now][to]=newnode();
            now=next1[now][to];
        }
        end1[now]=true;
    }
    void build(){
        fail[root]=root;
        queue<int> q;
        for(int i=0;i<4;++i){
            if(next1[root][i]==-1) next1[root][i]=root;
            else{
                fail[next1[root][i]]=root;
                q.push(next1[root][i]);
            }
        }
        while(!q.empty()){
            int now=q.front(); q.pop();
            if(end1[fail[now]]==true)///注意
                end1[now]=true;
            for(int i=0;i<4;++i){
                if(next1[now][i]==-1) next1[now][i]=next1[fail[now]][i];
                else {
                    fail[next1[now][i]]=next1[fail[now]][i];
                    q.push(next1[now][i]);
                }
            }
        }
    }
    Matrix getMatrix(){
        Matrix res = Matrix(L);
        for(int i=0;i<L;i++) for(int j=0;j<4;++j)
            if(!end1[next1[i][j]]) res.m[i][next1[i][j]]++;
        return res;
    }
};
int m,n;
char st[20];
Trie ac;
int main(){
    while(scanf("%d%d",&m,&n)!=EOF){
        ac.init();
        for(int i=0;i<m;++i){ scanf("%s",st); ac.insertnode(st); };
        ac.build();
        Matrix a=ac.getMatrix();
        a=doexpmat(a,n);
        int ans=0;
        for(int i=0;i<a.L;i++)
            ans=(ans+(int)a.m[0][i])%MOD;
        printf("%d\n",ans);
    }
    return 0;
}