POJ 2778 DNA Sequence(AC自动机+矩阵快速幂)

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

题意:
给出一些病毒字符串,只由A,T,C,G组成,现在要用着4个字符组成长度为n的字符串,且字符串中不可以包含任一病毒字符串,问共有多少种字符串。

 

思路:

回想一下离散数学中所学的邻接矩阵

而AC自动机的状态图就是一个有向图,我们只需要根据这个有向图建立邻接矩阵即可,因为不可以包含病毒串,所以只需要判断是否是字符串结尾,如果不是就说明可以连接起来。

注意在fail转移的时候传递字符串结尾标记。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<stack>
  7 #include<queue>
  8 #include<cmath>
  9 #include<map>
 10 #include<set>
 11 using namespace std;
 12 typedef long long ll;
 13 const int INF = 0x3f3f3f3f;
 14 const int maxn=10000+5;
 15 const int mod=100000;
 16 
 17 int n, m, num;
 18 char s[20];
 19 
 20 struct Trie
 21 {
 22     int son[10];
 23     int cnt;
 24     int fail;
 25 }t[150];
 26 
 27 
 28 struct Matrix
 29 {
 30     ll mat[200][200], n;
 31     Matrix(){}
 32     Matrix(int _n)
 33     {
 34         n=_n;
 35         for(int i=0;i<n;i++)
 36         for(int j=0;j<n;j++)
 37             mat[i][j]=0;
 38     }
 39     Matrix operator*(const Matrix& b) const
 40     {
 41         Matrix c=Matrix(n);
 42         for(int i=0;i<n;i++)
 43         {
 44             for(int j=0;j<n;j++)
 45             {
 46                 for(int k=0;k<n;k++)
 47                 {
 48                     c.mat[i][j]=(c.mat[i][j]+mat[i][k]*b.mat[k][j])%mod;
 49                 }
 50             }
 51         }
 52         return c;
 53     }
 54 };
 55 
 56 void init(int x)
 57 {
 58     t[x].fail=0;
 59     t[x].cnt=0;
 60     memset(t[x].son,0,sizeof(t[x].son));
 61 }
 62 
 63 int getch(char ch)
 64 {
 65     if(ch=='A')   return 1;
 66     if(ch=='T')   return 2;
 67     if(ch=='C')   return 3;
 68     if(ch=='G')   return 4;
 69 }
 70 
 71 void trie(char *s)
 72 {
 73     int n=strlen(s);
 74     int x=0;
 75     for(int i=0;i<n;i++)
 76     {
 77         int c=getch(s[i]);
 78         if(!t[x].son[c])
 79         {
 80             num++;
 81             init(num);
 82             t[x].son[c]=num;
 83         }
 84         x=t[x].son[c];
 85     }
 86     t[x].cnt=1;
 87 }
 88 
 89 void buildAC()
 90 {
 91     queue<int> Q;
 92     for(int i=1;i<=4;i++)  if(t[0].son[i])  Q.push(t[0].son[i]);
 93     while(!Q.empty())
 94     {
 95         int x=Q.front(); Q.pop();
 96         int fail=t[x].fail;
 97         for(int i=1;i<=4;i++)
 98         {
 99 
100             int y=t[x].son[i];
101             if(y)
102             {
103                 t[y].fail=t[fail].son[i];
104                 t[y].cnt|=t[t[fail].son[i]].cnt;  //这儿很重要,这个标记需要传递
105                 Q.push(y);
106             }
107             else t[x].son[i]=t[fail].son[i];
108         }
109     }
110 }
111 
112 Matrix getMatrix()
113 {
114     Matrix c=Matrix(num+1);
115     for(int i=0;i<=num;i++)
116     {
117         for(int j=1;j<=4;j++)
118         {
119             if(t[t[i].son[j]].cnt==0)  c.mat[i][t[i].son[j]]++;
120         }
121     }
122     return c;
123 }
124 
125 
126 void q_pow(Matrix base, int n)
127 {
128     Matrix ans=Matrix(base.n);
129     for(int i=0;i<ans.n;i++)   ans.mat[i][i]=1;
130     while(n)
131     {
132         if(n&1)  ans=ans*base;
133         base=base*base;
134         n>>=1;
135     }
136     int res=0;
137     for(int i=0;i<ans.n;i++)
138         res=(res+ans.mat[0][i])%mod;
139     printf("%d\n",res);
140 }
141 
142 int main()
143 {
144     //freopen("in.txt","r",stdin);
145     while(~scanf("%d%d",&m,&n))
146     {
147         init(0);
148         num=0;
149         for(int i=1;i<=m;i++)
150         {
151             scanf("%s",s);
152             trie(s);
153         }
154         buildAC();
155         Matrix c=getMatrix();
156         q_pow(c,n);
157     }
158     return 0;
159 }

 

posted @ 2017-08-27 08:40  Kayden_Cheung  阅读(205)  评论(0编辑  收藏  举报
//目录