poj2778 DNA Sequence(AC自動機+矩陣快速冪)
阿新 • • 發佈:2019-02-13
題意描述:給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; }