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

来源:互联网 发布:整站优化seo 上海 编辑:程序博客网 时间:2024/05/01 15:37

题目大意:

给出N个串,问在长度为L的所有串中,不包含任一已知串的个数有多少个。


思路分析:

已知一个矩阵A,A[i][j] 表示 节点i 到 节点 j 有一条变可以到达的方法数。

那么A^2 ,这个矩阵的 [i][j] 就代表这个节点 i 到节点 j 有两条边可以到达的方法数。

那么知道这个结论,我们要做的就是求一个节点到另外一个节点,要经过L条变(对应这长度为L的单词),而又要满足任意一条边都不能经过已知单词。


所以我们要用到ac自动机处理出所有已知的单词,在ac自动机上得到这个矩阵,使得任意两个节点之间都不是已知单词的结尾,我们才连一条边。

还要理解AC自动机的一点,就是在失配的时候,也就是要得到fail的时候,其实可以抽象成你fail的下一个节点就是这个节点的next节点。可以看成是一个单词。

那么也就要加上代码中标记上的那个注释上的判断。可以稍微想一想。


#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <queue>#define N 105#define maxn 10005using namespace std;typedef long long ll;const int mod = 100000;int rev[180];const char tab = 0;const int max_next = 4;int next[maxn][max_next],fail[maxn],num[maxn],siz;int newnode(){    for(int i=0;i<max_next;i++)        next[siz][i]=0;    fail[siz]=num[siz]=0;    return siz++;}void init(){    siz=0;    newnode();}void Insert(char *s,int len){    int p=0;    for(int i=0;i<len;i++)    {        int &x=next[p][rev[s[i]]];        p=x?x:x=newnode();    }    num[p]++;}void acbuild(){    queue<int>Q;    Q.push(0);    while(!Q.empty())    {        int temp=Q.front();        Q.pop();        for(int i=0;i<max_next;i++)        {            int v=next[temp][i];            if(v==0)next[temp][i]=next[fail[temp]][i];            else Q.push(v);            if(temp!=0)fail[v]=next[fail[temp]][i];            if(num[next[fail[temp]][i]])num[next[temp][i]]++;//---------        }    }}struct matrix{    int r,c;    ll data[N][N];    matrix(){}    matrix(int _r,int _c):r(_r),c(_c){}    friend matrix operator * (const matrix A,const matrix B)    {        matrix res;        res.r=A.r;res.c=B.c;        memset(res.data,0,sizeof res.data);        for(int i=0;i<A.r;i++)        {            for(int j=0;j<B.c;j++)            {                for(int k=0;k<A.c;k++)                {                    if(A.data[i][k] && B.data[k][j]){                        res.data[i][j]+=A.data[i][k]*B.data[k][j];                        res.data[i][j]%=mod;                    }                }            }        }        return res;    }    friend matrix operator + (const matrix A,const matrix B)    {        matrix res;        res.r=A.r;res.c=A.c;        memset(res.data,0,sizeof res.data);        for(int i=0;i<A.r;i++)        {            for(int j=0;j<A.c;j++)            {                res.data[i][j]=A.data[i][j]+B.data[i][j];                res.data[i][j]%=mod;            }        }        return res;    }    friend matrix operator - (const matrix A,const matrix B)    {        matrix res;        res.r=A.r;res.c=A.c;        memset(res.data,0,sizeof res.data);        for(int i=0;i<A.r;i++)        {            for(int j=0;j<A.c;j++)            {                res.data[i][j]=A.data[i][j]-B.data[i][j];                res.data[i][j]=(res.data[i][j]%mod+mod)%mod;            }        }        return res;    }    friend matrix operator ^ (matrix A,int n)    {        matrix res;        res.r=A.r;res.c=A.c;        memset(res.data,0,sizeof res.data);        for(int i=0;i<A.r;i++)res.data[i][i]=1;        while(n)        {            if(n&1)res=res*A;            A=A*A;            n>>=1;        }        return res;    }    void print()    {        for(int i=0;i<r;i++)        {            for(int j=0;j<c;j++)                printf("%d ",data[i][j]);            puts("");        }    }}E,zero;char word[10005];int main(){    for(int i=0;i<N;i++)        E.data[i][i]=1;    rev['A']=0;    rev['C']=1;    rev['G']=2;    rev['T']=3;    int n,L;    while(scanf("%d%d",&n,&L)!=EOF)    {        init();        for(int i=1;i<=n;i++)        {            scanf("%s",word);            Insert(word,strlen(word));        }        acbuild();        matrix origin(siz,siz);        for(int i=0;i<siz;i++)        {            if(!num[i])            {                for(int d=0;d<4;d++)                {                    if(!num[next[i][d]])                    {                        origin.data[i][next[i][d]]++;                    }                }            }        }        origin= origin^L;        int ans=0;        for(int i=0;i<siz;i++)        {            if(!num[i])                ans=(ans+origin.data[0][i])%mod;        }        printf("%d\n",ans);    }    return 0;}


0 0
原创粉丝点击