POJ 2778(自动机+矩阵幂乘(字符串果然是个坑爹玩应!))
参考:http://hi.baidu.com/ccsu_010/item/7847a3c17f6fe2bc0d0a7b89
关键是状态转移,矩阵就是解决状态转移的!(比较难)
数据量:1 <= n <=2000000000(明显快速算法!)
Description
It's well known that DNA Sequence is a sequence only contains A, C, T and G, and it's very useful to analyze a segment of DNA Sequence,For example, if a animal's DNA sequence contains segment ATC then it may mean that the animal may have a genetic disease. Until now scientists have found several those segments, the problem is how many kinds of DNA sequences of a species don't contain those segments.
Suppose that DNA sequences of a species is a sequence that consist of A, C, T and G,and the length of sequences is a given integer n.
Suppose that DNA sequences of a species is a sequence that consist of A, C, T and G,and the length of sequences is a given integer n.
Input
First line contains two integer m (0 <= m <= 10), n (1 <= n <=2000000000). Here, m is the number of genetic disease segment, and n is the length of sequences.
Next m lines each line contain a DNA genetic disease segment, and length of these segments is not larger than 10.
Next m lines each line contain a DNA genetic disease segment, and length of these segments is not larger than 10.
Output
An integer, the number of DNA sequences, mod 100000.
Sample Input
4 3 AT AC AG AA
Sample Output
36
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//#pragma comment(linker, "/STACK:102400000") #include<cstdlib> #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<set> #include<map> #include<list> #include<queue> #include<stack> #include<vector> #define tree int o,int l,int r #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define lo o<<1 #define ro o<<1|1 #define pb push_back #define mp make_pair #define ULL unsigned long long #define LL long long #define inf 0x7fffffff #define eps 1e-7 #define N 109 #define M 4 #define mod 100000 using namespace std; int m,n,T,t,x,y,u; int ch[N][4]; int v[N]; int f[N],last[N],num; LL ma[N][N],temp[N][N]; void clear()//Trie树初始化 { memset(ma,0,sizeof(ma)); num=1; memset(ch[0],0,sizeof(ch[0])); memset(v,0,sizeof(v)); memset(last,0,sizeof(last)); } int idx(char c) { switch(c) { case 'A':return 0; case 'C':return 1; case 'G':return 2; case 'T':return 3; } return 0; } void insert(char str[],int value)//建Trie树 { int len=strlen(str); int u=0; for (int i=0; i<len; ++i ) { int c=idx(str[i]); if(!ch[u][c])//保存的是结点坐标 { memset(ch[num],0,sizeof(ch[num])); ch[u][c]=num++;// } u=ch[u][c]; } v[u]=value; } void getac() { queue<int> q;//保存的节点下标 f[0]=0; for (int c=0; c<M; ++c ) { int u=ch[0][c]; if(u)//不需要优化的else { q.push(u); f[u]=0; last[u]=v[u];//WA,可能有长度为1的串 } } while(!q.empty()) { int r=q.front(); q.pop(); for (int c=0; c<M; ++c ) { int u=ch[r][c]; if(u) { q.push(u); int s=f[r]; f[u]=ch[s][c]; last[u]=(v[u]||last[f[u]]);//改 } else //重要优化 ch[r][c]=ch[f[r]][c]; } } } char str[20]; void build()//构造矩阵!!! { for(int i=0;i<num;i++) { for(int j=0;j<4;j++) { int u=ch[i][j]; if(last[u]==0) ma[i][u]++; } } } void malti(LL a[][N],LL b[][N],int n) { LL c[N][N]={0}; for(int i=0;i<n;i++) for(int j=0;j<n;j++) for(int k=0;k<n;k++) { c[i][j]+=a[i][k]*b[k][j]; c[i][j]%=mod; } memcpy(a,c,sizeof(c)); } void mat(LL ma[][N],int n,int num) { memset(temp,0,sizeof(temp)); for(int i=0;i<num;i++) temp[i][i]=1; while(n) { if(n&1) { malti(temp,ma,num); } malti(ma,ma,num); n>>=1; } memcpy(ma,temp,sizeof(temp)); } int main() { #ifndef ONLINE_JUDGE freopen("ex.in","r",stdin); #endif int ncase=0; // scanf("%d",&T); // while(T--) while(scanf("%d%d%*c",&m,&n)==2) { clear(); while(m--) { scanf("%s",str); insert(str,1); } getac(); build(); // print2(ma,num,num); mat(ma,n,num); int ans=0; for(int i=0;i<num;i++) { ans+=ma[0][i]; ans%=mod; } printf("%d\n",ans); } return 0; }