【POJ2778】DNA Sequence 【AC自动机,dp,矩阵快速幂】

题意

  题目给出m(m<=10)个仅仅由A,T,C,G组成的单词(单词长度不超过10),然后给出一个整数n(n<=2000000000),问你用这四个字母组成一个长度为n的长文本,有多少种组成方法可以使得它不含任何一个给出的单词。

分析

  当时一看以为是跟训练指南上(UVA11468)一样的题,感觉只有四个字母并且单词数量和长度也比较小,但是一看给出的n有点懵逼。如果再按照书上建立AC自动机以后直接跑DP的方法肯定是不行了。然后我们就要用到,递推利器,矩阵快速幂。

  我们还是按照套路先把AC自动机建出来,然后将每个单词结点设为非法结点,题目变成在AC自动机中走n步不通过非法结点的方案数。然后设f[i][j]是当前在结点i,已经走了j步,且未走过非法结点的方案数。然后怎么转移呢?

  f[i][j]=A(0,i)*f[0][j-1]+A(1,i)*f[1][j-1]+...+A(sz-1,i)f[sz-1][j-1]。其中A(i,j)的含义就是从i到j有几条直接连接的边。那么将这个dp方程拆开来看

  

  f0[i]=A(0,0)*f[0][i-1]+A(1,0)*f[1][i-1]+....+A(sz-1,0)*fsz-1[i-1]

  f1[i]=A(0,1)*f[0][i-1]+A(1,1)*f[1][i-1]+....+A(sz-1,1)*fsz-1[i-1]

  .

  .

  fsz-1[i]=A(0,sz-1)*f[0][i-1]+A(1,sz-1)*f[1][i-1]+...+A(sz-1,sz-1)*fsz-1[i-1]

 然后根据这个我们就很好建立转移矩阵

 *

  (第一次学会用公式编辑器不过好像还是贼丑)

   然后建立这个大的转移矩阵,矩阵的(i,j)为结点i到结点j的直接路径的条数,然后跑一个矩阵快速幂。 

   最后把从0到sz-1结点的f(n)的值全部加起来就是答案了。

    对了这个题需要用long long

   下面是代码

   

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5 #include <queue>
  6 #include <map>
  7 
  8 using namespace std;
  9 const int maxnode=1100;
 10 const int MOD=100000;
 11 map<char,int>M;
 12 struct AC_Automata{
 13     int ch[maxnode][4],f[maxnode],last[maxnode],val[maxnode],match[maxnode];
 14     int sz;
 15     int idx(char c){
 16         return M[c];
 17     }
 18     void init(){
 19         sz=1;
 20         memset(ch[0],0,sizeof(ch[0]));
 21         memset(match,0,sizeof(match));
 22         val[0]=0;
 23     }
 24     void insert(char *s){
 25         int n=strlen(s),u=0;
 26         for(int i=0;i<n;i++){
 27             int c=idx(s[i]);
 28             if(!ch[u][c]){
 29                 ch[u][c]=sz;
 30                 memset(ch[sz],0,sizeof(ch[sz]));
 31                 val[sz++]=0;
 32             }
 33             u=ch[u][c];
 34         }
 35         val[u]=1;
 36         match[u]=1;
 37     }
 38     void getFail(){
 39         queue<int>q;
 40         last[0]=f[0]=0;
 41         for(int i=0;i<4;i++){
 42             int u=ch[0][i];
 43             if(u){
 44                 q.push(u);
 45                 f[u]=last[u]=0;
 46             }
 47         }
 48         while(!q.empty()){
 49             int r=q.front();q.pop();
 50             for(int i=0;i<4;i++){
 51                 int u=ch[r][i];
 52                 if(!u){
 53                     ch[r][i]=ch[f[r]][i];
 54                     continue;
 55                 }
 56                 q.push(u);
 57                 int v=f[r];
 58                 while(v&&!ch[v][i])v=f[v];
 59                 f[u]=ch[v][i];
 60                 match[u]|=match[f[u]];
 61             }
 62         }
 63     }
 64 }ac;
 65 const int maxN=101;
 66 struct Matrix{
 67     long long a[maxN][maxN];
 68     void init(){
 69         memset(a,0,sizeof(a));
 70         for(int i=0;i<ac.sz;i++)
 71             a[i][i]=1;
 72     }
 73 };
 74 Matrix mul(Matrix a,Matrix b){
 75     Matrix res;
 76     for(int i=0;i<ac.sz;i++){
 77         for(int j=0;j<ac.sz;j++){
 78             res.a[i][j]=0;
 79             for(int k=0;k<ac.sz;k++){
 80                 res.a[i][j]+=a.a[i][k]*b.a[k][j];
 81                 res.a[i][j]%=MOD;
 82             }
 83         }
 84     }
 85     return res;
 86 }
 87 Matrix qpow(Matrix a,int k){
 88     Matrix res;
 89     res.init();
 90     while(k){
 91         if(k%2)res=mul(res,a);
 92         a=mul(a,a);
 93         k/=2;
 94     }
 95     return res;
 96 }
 97 int n,m;
 98 char s[30];
 99 
100 int main(){
101     M['A']=0,M['C']=1,M['T']=2,M['G']=3;
102     ac.init();
103     scanf("%d%d",&m,&n);
104     for(int i=1;i<=m;i++){
105         scanf("%s",s);
106         ac.insert(s);
107     }
108     ac.getFail();
109     Matrix A;
110     for(int i=0;i<ac.sz;i++){
111             if(!ac.match[i])
112         for(int j=0;j<4;j++){
113             int u=ac.ch[i][j];
114             if(!ac.match[u])
115             A.a[i][u]++;
116         }
117     }
118     /*for(int i=0;i<ac.sz;i++){
119         for(int j=0;j<ac.sz;j++){
120             printf("%d ",A.a[i][j]);
121         }
122         printf("\n");
123     }*/
124 
125     Matrix S;
126     S.a[0][0]=1;
127     Matrix ANS;
128     ANS=qpow(A,n);
129     ANS=mul(S,ANS);
130     long long ans=0; 
131     for(int i=0;i<=ac.sz;i++)
132         ans+=ANS.a[0][i];
133     printf("%d\n",ans%MOD);
134 return 0;
135 }
View Code

 

posted @ 2018-07-21 01:04  蒟蒻LQL  阅读(588)  评论(0编辑  收藏  举报