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

来源:互联网 发布:真小人 伪君子知乎 编辑:程序博客网 时间:2024/05/22 05:06

转载请注明出处,谢谢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 longusing 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;}




原创粉丝点击