oneman233

POJ 2778 DNA Sequence(AC自动机加矩阵快速幂)

关于矩阵的幂,参见:http://www.mynameisdhr.com/%e7%9f%a9%e9%98%b5%e7%9a%84%e5%b9%82/

题意是给你m个致病DNA序列,只包含四种字符ATCG,现在问你任意的长度为n的DNA序列当中有多少种不包含致病DNA序列的

首先建立AC自动机,考虑一些fail树上的性质,某个节点的fail边指向的是某个串的前缀与当前串后缀相同的位置

考虑邻接矩阵的性质,边权为1的无向图构建的允许重边的邻接矩阵的n次方是从i走到j的路径条数

构建邻接矩阵,以病毒串结尾的位置设为0,注意的是如果某个点的fail边指向病毒串结尾位置,这个点也要设为0

狗屎POJ不能用万能头

代码:

#include <cstring>
#include <cstdio>
#include <queue>
//#define int long long
using namespace std;
typedef long long ll;
const ll mod=100000;
const int maxn=105;

ll init[101][101];
int n,m;
char s[maxn];

struct AC_AUTO{
    int c[maxn*23][4],cnt,fl[maxn*23];
    bool ed[maxn*23];
    queue<int> q;
    int to(char c){
        if(c=='A') return 0;
        else if(c=='C') return 1;
        else if(c=='G') return 2;
        else if(c=='T') return 3;
    }
    void ins(char *s){
        int l=strlen(s),now=0;
        for(int i=0;i<l;++i){
            if(!c[now][to(s[i])]) c[now][to(s[i])]=++cnt;
            now=c[now][to(s[i])];
        }
        ed[now]=1;
    }
    void build(){
        for(int i=0;i<=3;++i){
            if(c[0][i]){
                fl[c[0][i]]=0;
                q.push(c[0][i]);
            }
        }
        while(!q.empty()){
            int f=q.front();
            q.pop();
            if(ed[fl[f]]) ed[f]=1;//
            for(int i=0;i<=3;++i){
                if(c[f][i]){ 
                    fl[c[f][i]]=c[fl[f]][i];
                    q.push(c[f][i]);
                }
                else c[f][i]=c[fl[f]][i];
            }
        }
    }
}ac;

void mul(ll x[101][101],ll y[101][101])
{
    ll tmp[101][101];
    memset(tmp,0,sizeof(tmp));
    for(int k=0;k<=ac.cnt;k++)
        for(int i=0;i<=ac.cnt;i++)
            for(int j=0;j<=ac.cnt;j++)
                tmp[i][j]=(tmp[i][j]+x[i][k]*y[k][j])%mod;
    for(int i=0;i<=ac.cnt;i++)
        for(int j=0;j<=ac.cnt;j++)
            x[i][j]=tmp[i][j];    
}

void qpow(int b){
    ll ans[101][101];
    memset(ans,0,sizeof(ans));
    for(int i=0;i<=ac.cnt;++i)
        ans[i][i]=1;
    while(b){
        if(b&1) mul(ans,init);
        mul(init,init);
        b>>=1;
    }
    for(int i=0;i<=ac.cnt;i++)
        for(int j=0;j<=ac.cnt;j++)
            init[i][j]=ans[i][j];
}

ll query(){
    memset(init,0,sizeof(init));
    for(int i=0;i<=ac.cnt;++i){
        if(ac.ed[i]) continue;//
        for(int j=0;j<=3;++j){
            int nxt=ac.c[i][j];
            if(!ac.ed[nxt]) init[i][nxt]++;
        }
    }
    qpow(m);
    ll res=0;
    for(int i=0;i<=100;++i){
        res=(res+init[0][i])%mod;
    }
    return res;
}

signed main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%s",s);
        ac.ins(s);
    }
    ac.build();
    printf("%lld",query());
    return 0;
}

 

posted on 2019-09-10 17:53  oneman233  阅读(140)  评论(0)    收藏  举报

导航