poj2778 DNA Sequence(AC自动机+矩阵快速幂)

题目链接:点击打开链接

题意描述:给m字符串,这m个字符串是带有病毒的DNA。然后问一个长度为n的字符串不带有任何病毒有多少中可能?所有字符串之后ACGT这几个字符串组成


解题思路:AC自动机+矩阵快速幂

前置内容:邻接矩阵幂的含义:点击打开链接

分析:首先根据题意先建一个AC自动机,其实AC自动机本身就是一张图,AC自动机中的每个结点就相当于图中的顶点,每个转移A、C、G、T就相当于一条边;根据邻接矩阵幂的含义,我们发现求长度为n的字符串的个数就相当于从起点在图中走n步所能到达的所点的方案数的和,而n又很大,我们可以使用矩阵快速幂;但是本题有限制就是不能带有某些字符串,言外之意就是图中有些节点不能经过,根据AC自动机中的end[i]我们可以将这种情况去掉


代码:

#include <cstdio>
#include <cstring>
#include <queue>
#define MOD 100000
typedef long long ll;
using namespace std;
struct Matrix{
    ll m[110][110];
    int L;
    Matrix(int len){
        L=len;
        for(int i=0;i<L;++i)
            for(int j=0;j<L;++j)
                m[i][j]=0;
    }
};
Matrix mat(Matrix a,Matrix b){
    Matrix c(a.L);
    for(int i=0;i<c.L;++i)
        for(int j=0;j<c.L;++j){
            for(int k=0;k<c.L;++k){
                c.m[i][j]+=(a.m[i][k]*b.m[k][j]);
                c.m[i][j]%=MOD;
            }
        }
    return c;
}
Matrix doexpmat(Matrix a,int num){
    Matrix t(a.L);
    for(int i=0;i<t.L;++i)
        t.m[i][i]=1;
    while(num){
        if(num&1) t=mat(a,t);
        num=num>>1;
        a=mat(a,a);
    }
    return t;
}
struct Trie{
    int next1[110][4],fail[110];
    bool end1[110];
    int root,L;
    int newnode(){
        for(int i=0;i<4;++i) next1[L][i]=-1;
        end1[L++]=false;
        return L-1;
    }
    void init(){ L=0; root=newnode(); }
    int getchs(char ch){
        switch(ch){
        case 'A': return 0;break;
        case 'C': return 1;break;
        case 'G': return 2;break;
        case 'T': return 3;break;
        }
    }
    void insertnode(char* str){
        int now=root;
        int len=strlen(str);
        for(int i=0;i<len;++i){
            int to=getchs(str[i]);
            if(next1[now][to]==-1)
                next1[now][to]=newnode();
            now=next1[now][to];
        }
        end1[now]=true;
    }
    void build(){
        fail[root]=root;
        queue<int> q;
        for(int i=0;i<4;++i){
            if(next1[root][i]==-1) next1[root][i]=root;
            else{
                fail[next1[root][i]]=root;
                q.push(next1[root][i]);
            }
        }
        while(!q.empty()){
            int now=q.front(); q.pop();
            if(end1[fail[now]]==true)///注意
                end1[now]=true;
            for(int i=0;i<4;++i){
                if(next1[now][i]==-1) next1[now][i]=next1[fail[now]][i];
                else {
                    fail[next1[now][i]]=next1[fail[now]][i];
                    q.push(next1[now][i]);
                }
            }
        }
    }
    Matrix getMatrix(){
        Matrix res = Matrix(L);
        for(int i=0;i<L;i++) for(int j=0;j<4;++j)
            if(!end1[next1[i][j]]) res.m[i][next1[i][j]]++;
        return res;
    }
};
int m,n;
char st[20];
Trie ac;
int main(){
    while(scanf("%d%d",&m,&n)!=EOF){
        ac.init();
        for(int i=0;i<m;++i){ scanf("%s",st); ac.insertnode(st); };
        ac.build();
        Matrix a=ac.getMatrix();
        a=doexpmat(a,n);
        int ans=0;
        for(int i=0;i<a.L;i++)
            ans=(ans+(int)a.m[0][i])%MOD;
        printf("%d\n",ans);
    }
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值