转载请注明出处,谢谢http://blog.csdn.net/acm_cxlove/article/details/7854526 by---cxlove
题目:长度为N的DNA串不包含模式串的有多少个。
http://poj.org/problem?id=2778
N为20000000000,如此大的规模,肯定是lg(N)的算法,就会想到矩阵。
长度为10的模式串,10个,而且只有4个字母,最多不超过100个状态
建立AC自动机,记录里面的转移。
和基本的AC自动机有一点点不一样,如果某个结点的某个孩子结点为空,其它它还是可以转移的。
也就是他是可以存在后继状态,如果这个结点为根,那么还是转移到根,否则就转向失败指针指向的孩子结点。
需要建立转移矩阵,使用静态Trie,便于建立矩阵,两个状态之间可以转移,相当于存在一条路径,最终要求的是从空开始路径长度为n的个数。
不知道为什么,把Trie删掉反而会RE。
另外会超int,需要用64位整数。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 100005
#define MOD 100000
#define LL long long
using namespace std;
struct Trie{
Trie *next[4];
Trie *fail;
int kind,isword;
};
Trie *que[N],s[N];
int idx;
int id(char ch){
if(ch=='A') return 0;
else if(ch=='T') return 1;
else if(ch=='C') return 2;
return 3;
}
Trie *NewTrie(){
//静态Trie
Trie *tmp=&s[idx];
for(int i=0;i<4;i++) tmp->next[i]=NULL;
tmp->isword=0;
tmp->fail=NULL;
tmp->kind=idx++;
return tmp;
}
void Insert(Trie *root,char *s,int len){
Trie *tmp=root;
for(int i=0;i<len;i++){
if(tmp->next[id(s[i])]==NULL) tmp->next[id(s[i])]=NewTrie();
tmp=tmp->next[id(s[i])];
}
tmp->isword=1;
}
void Bulid_fail(Trie *root){
int tail=0,head=0;
que[tail++]=root;
root->fail=NULL;
while(head<tail){
Trie *tmp=que[head++];
for(int i=0;i<4;i++){
if(tmp->next[i]==NULL){
if(tmp==root) tmp->next[i]=root;
else tmp->next[i]=tmp->fail->next[i];
}
else{
if(tmp==root) tmp->next[i]->fail=root;
else{
tmp->next[i]->fail=tmp->fail->next[i];
if(tmp->next[i]->fail->isword)
tmp->next[i]->isword=1;
}
que[tail++]=tmp->next[i];
}
}
}
}
char str[15];
struct Matrix{
LL m[101][101];
}Init;
Matrix mult(Matrix m1,Matrix m2){
Matrix ans;
memset(ans.m,0,sizeof(ans.m));
for(int i=0;i<idx;i++){
for(int k=0;k<idx;k++){
if(m1.m[i][k]==0) continue;
for(int j=0;j<idx;j++){
ans.m[i][j]+=(LL)m1.m[i][k]*m2.m[k][j];
if(ans.m[i][j]>=MOD) ans.m[i][j]%=MOD;
}
}
}
return ans;
}
Matrix PowMod(Matrix m1,int n){
Matrix ans;
for(int i=0;i<idx;i++) for(int j=0;j<idx;j++) ans.m[i][j]=i==j;
while(n){
if(n&1) ans=mult(ans,m1);
m1=mult(m1,m1);
n>>=1;
}
return ans;
}
int main(){
int m,n;
while(scanf("%d%d",&m,&n)!=EOF){
idx=0;
Trie *root=NewTrie();
for(int i=0;i<m;i++){
scanf("%s",str);
Insert(root,str,strlen(str));
}
Bulid_fail(root);
memset(Init.m,0,sizeof(Init.m));
for(int i=0;i<idx;i++){
for(int j=0;j<4;j++){
Trie *son=s[i].next[j];
if(!son->isword&&!s[i].isword)
Init.m[i][son->kind]++;
}
}
Init=PowMod(Init,n);
LL ans=0;
for(int i=0;i<idx;i++){
ans+=Init.m[0][i];
if(ans>=MOD) ans-=MOD;
}
printf("%I64d\n",ans);
}
return 0;
}