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

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

题意:有多少种长度n位DNA串不含有指定的病毒片段。

思路:首先,建立自动机,其实也就是一个有向图,则长度为n就好比是在图上走n次,也就是图对应矩阵的n次方。




const int mod=100000;
const int N=205;


struct node
{
    int next[4],fail,flag;

    void init()
    {
        clr(next,0);
        fail=-1;
        flag=0;
    }
};

node a[N];
int e,n,m;
char s[N];

int get(char x)
{
    if(x=='A') return 0;
    else if(x=='T') return 1;
    else if(x=='G') return 2;
    return 3;
}


void insert(char s[])
{
    int i,k,p=0;
    for(i=0;s[i];i++)
    {
        k=get(s[i]);
        if(a[p].next[k]==0)
        {
            a[e].init();
            a[p].next[k]=e++;
        }
        p=a[p].next[k];
    }
    a[p].flag=1;
}

queue<int> Q;

void build()
{
    Q.push(0);
    int i,j,k,p,q;
    while(!Q.empty())
    {
        k=Q.front();
        Q.pop();
        for(i=0;i<4;i++)
        {
            if(a[k].next[i])
            {
                p=a[k].next[i];
                q=a[k].fail;
                while(q!=-1&&!a[q].next[i]) q=a[q].fail;
                if(q==-1) a[p].fail=0;
                else
                {
                    a[p].fail=a[q].next[i];
                    a[p].flag|=a[a[p].fail].flag;
                }
                Q.push(p);
            }
            else
            {
                q=a[k].fail;
                while(q!=-1&&!a[q].next[i]) q=a[q].fail;
                if(q==-1) a[k].next[i]=0;
                else a[k].next[i]=a[q].next[i];
            }
        }
    }
}


int b[N][N],d[N][N];

void mul(int a[][N],int b[][N])
{
    int i,j,k,c[N][N]={0};
    FOR0(k,e) FOR0(i,e) FOR0(j,e)
    {
        c[i][j]+=(i64)a[i][k]*b[k][j]%mod;
        c[i][j]%=mod;
    }
    FOR0(i,e) FOR0(j,e) a[i][j]=c[i][j];
}

int main()
{
    RD(m,n);a[0].init();e=1;
    int i,j,k;
    FOR0(i,m)
    {
        RD(s);
        insert(s);
    }
    build();
    FOR0(i,e) if(!a[i].flag) FOR0(j,4)
    {
        k=a[i].next[j];
        if(!a[k].flag) b[i][k]++;
    }
    FOR0(i,e) d[i][i]=1;
    while(n)
    {
        if(n&1) mul(d,b);
        mul(b,b);
        n>>=1;
    }
    i64 ans=0;
    FOR0(i,e) if(!a[i].flag)ans+=d[0][i];
    ans%=mod;
    PR(ans);
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值