POJ2778 DNA Sequence AC自动机+矩阵二分

  题目链接:http://poj.org/problem?id=2778

  [摘自Matrix67]  题目大意是,检测所有可能的n位DNA串有多少个DNA串中不含有指定的病毒片段。合法的DNA只能由ACTG四个字符构成。题目将给出10个以内的病毒片段,每个片段长度不超过10。数据规模n<=2 000 000 000。
  下面的讲解中我们以ATC,AAA,GGC,CT这四个病毒片段为例,说明怎样像上面的题一样通过构图将问题转化为例题8。我们找出所有病毒片段的前缀,把n位DNA分为以下7类:以AT结尾、以AA结尾、以GG结尾、以?A结尾、以?G结尾、以?C结尾和以??结尾。其中问号表示“其它情况”,它可以是任一字母,只要这个字母不会让它所在的串成为某个病毒的前缀。显然,这些分类是全集的一个划分(交集为空,并集为全集)。现在,假如我们已经知道了长度为n-1的各类DNA中符合要求的DNA个数,我们需要求出长度为n时各类DNA的个数。我们可以根据各类型间的转移构造一个边上带权的有向图。例如,从AT不能转移到AA,从AT转移到??有4种方法(后面加任一字母),从?A转移到AA有1种方案(后面加个A),从?A转移到??有2种方案(后面加G或C),从GG到??有2种方案(后面加C将构成病毒片段,不合法,只能加A和T)等等。这个图的构造过程类似于用有限状态自动机做串匹配。然后,我们就把这个图转化成矩阵,让这个矩阵自乘n次即可。最后输出的是从??状态到所有其它状态的路径数总和。
  题目中的数据规模保证前缀数不超过100,一次矩阵乘法是三方的,一共要乘log(n)次。因此这题总的复杂度是100^3 * log(n),AC了。

  Example:       

      2 3

      AG

      CG

  状态转移图:

       

  要注意当前前缀 i 匹配的前缀 j 可能不是可行的前缀。

  1 //STATUS:C++_AC_313MS_624KB
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include<string.h>
  5 #include<math.h>
  6 #include<iostream>
  7 #include<string>
  8 #include<algorithm>
  9 #include<vector>
 10 #include<queue>
 11 #include<stack>
 12 #include<map>
 13 #include<set>
 14 using namespace std;
 15 //define
 16 #define pii pair<int,int>
 17 #define mem(a,b) memset(a,b,sizeof(a))
 18 #define lson l,mid,rt<<1
 19 #define rson mid+1,r,rt<<1|1
 20 #define PI acos(-1.0)
 21 //typedef
 22 typedef __int64 LL;
 23 typedef unsigned __int64 ULL;
 24 //const
 25 const int N=101;
 26 const int INF=0x3f3f3f3f;
 27 const int MOD=100000,STA=8000010;
 28 const LL LNF=1LL<<60;
 29 const double EPS=1e-8;
 30 const double OO=1e15;
 31 //Daily Use ...
 32 template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
 33 template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
 34 template<class T> inline T Min(T a,T b){return a<b?a:b;}
 35 template<class T> inline T Max(T a,T b){return a>b?a:b;}
 36 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}
 37 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}
 38 template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));}
 39 template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));}
 40 //End
 41 
 42 int idx[N];
 43 int ch[N][4];
 44 int val[N],f[N],sta[N];
 45 int sz,n,m;
 46 int size;
 47 
 48 struct Matrix{
 49     LL ma[N][N];
 50     Matrix friend operator * (const Matrix a,const Matrix b){
 51         Matrix ret;
 52         mem(ret.ma,0);
 53         int i,j,k;
 54         for(k=0;k<size;k++)
 55             for(i=0;i<size;i++)
 56                 for(j=0;j<size;j++)
 57                     ret.ma[i][j]=(ret.ma[i][j]+a.ma[i][k]*b.ma[k][j])%MOD;
 58         return ret;
 59     }
 60 }ans,mta;
 61 
 62 void mutilpow(LL k)
 63 {
 64     int i,j;
 65     mem(ans.ma,0);
 66     for(i=0;i<size;i++)
 67         ans.ma[i][i]=1;
 68     for(;k;k>>=1){
 69         if(k&1)ans=ans*mta;
 70         mta=mta*mta;
 71     }
 72 }
 73 
 74 void init(){sz=1;mem(ch[0],0);}
 75 
 76 void insert(char *s,int v){
 77     int i,len=strlen(s),id,u=0;
 78     for(i=0;i<len;i++){
 79         id=idx[s[i]];
 80         if(!ch[u][id]){
 81             mem(ch[sz],0);
 82             val[sz]=0;
 83             ch[u][id]=sz++;
 84         }
 85         u=ch[u][id];
 86     }
 87     val[u]=v;
 88 }
 89 
 90 void getFail()
 91 {
 92     int u,v,r,c;
 93     queue<int> q;
 94     mem(mta.ma,0);
 95     f[0]=0;
 96     sta[0]=size++;
 97     for(c=0;c<4;c++){
 98         u=ch[0][c];
 99         if(u){
100             f[u]=0;q.push(u);
101             if(!val[u]){
102                 sta[u]=size++;
103                 mta.ma[0][sta[u]]++;
104             }
105         }
106         else mta.ma[0][0]++;
107     }
108     while(!q.empty()){
109         r=q.front();q.pop();
110         if(sta[r]==-1)continue;
111         for(c=0;c<4;c++){
112             u=ch[r][c];
113             if(!u){
114                 v=ch[r][c]=ch[f[r]][c];
115                 if(sta[v]==-1)continue;
116                 mta.ma[sta[r]][sta[v]]++;
117             }
118             else {
119                 q.push(u);
120                 v=f[r];
121                 while(v && !ch[v][c])v=f[v];
122                 f[u]=ch[v][c];
123                 if(val[u] || sta[f[u]]==-1)continue;
124                 sta[u]=size++;
125                 mta.ma[sta[r]][sta[u]]++;
126             }
127         }
128     }
129 }
130 
131 int main()
132 {
133  //   freopen("in.txt","r",stdin);
134     int i,j;
135     LL sum;
136     char s[20];
137     idx['A']=0;idx['C']=1;idx['T']=2,idx['G']=3;
138     while(~scanf("%d%d",&m,&n))
139     {
140         init();
141         for(i=0;i<m;i++){
142             scanf("%s",s);
143             insert(s,1);
144         }
145 
146         mem(sta,-1);
147         size=0;
148         getFail();
149         mutilpow(n);
150         for(i=sum=0;i<size;i++){
151             sum+=ans.ma[0][i];
152         }
153 
154         printf("%I64d\n",sum%MOD);
155     }
156     return 0;
157 }
原文地址:https://www.cnblogs.com/zhsl/p/3056314.html