• POJ 2778 DNA Sequence(AC自动机 + 矩阵快速幂)题解


    题意:给出m个模式串,要求你构造长度为n(n <= 2000000000)的主串,主串不包含模式串,问这样的主串有几个

    思路:因为要不包含模式串,显然又是ac自动机。因为n很大,所以用dp不太好。

    在图论中,如果我们知道一个图的邻接矩阵A,$A_{ij}$ = 1表示i走一步到j有一条路,那么$A^n$中的$A_{ij}$就是这个图中从i走n步到j的路径数。

    所以用ac自动机我们创造一个所有后缀的邻接矩阵A,那么用矩阵快速幂$A^n$就求出了所有的路径数,$sum_{i = 1}^n A_{0i}$就是从root走到所有可行后缀的所有走法。

    代码:

    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include <iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 100 + 5;
    const int M = 50 + 5;
    const ull seed = 131;
    const double INF = 1e20;
    const int MOD = 100000;
    int m, tn;
    ll n;
    struct Mat{
        ll s[maxn][maxn];
    };
    Mat mul(Mat &a, Mat &b){
        Mat t;
        memset(t.s, 0, sizeof(t.s));
        for(int i = 0; i < tn; i++){
            for(int j = 0; j < tn; j++){
                for(int k = 0; k < tn; k++){
                    t.s[i][j] = (t.s[i][j] + a.s[i][k] * b.s[k][j])%MOD;
                }
            }
        }
        return t;
    }
    Mat ppow(Mat a, ll b){
        Mat ret;
        memset(ret.s, 0, sizeof(ret.s));
        for(int i = 0; i < maxn; i++) ret.s[i][i] = 1;
        while(b){
            if(b & 1) ret = mul(ret, a);
            a = mul(a, a);
            b >>= 1;
        }
        return ret;
    }
    int id(char a){
        if(a == 'A') return 0;
        if(a == 'T') return 1;
        if(a == 'C') return 2;
        if(a == 'G') return 3;
    }
    struct Aho{
        struct state{
            int next[4];
            int fail, cnt;
        }node[maxn];
        int size;
        queue<int> q;
    
        void init(){
            size = 0;
            newtrie();
            while(!q.empty()) q.pop();
        }
    
        int newtrie(){
            memset(node[size].next, 0, sizeof(node[size].next));
            node[size].cnt = node[size].fail = 0;
            return size++;
        }
    
        void insert(char *s){
            int len = strlen(s);
            int now = 0;
            for(int i = 0; i < len; i++){
                int c = id(s[i]);
                if(node[now].next[c] == 0){
                    node[now].next[c] = newtrie();
                }
                now = node[now].next[c];
            }
            node[now].cnt = 1;
        }
    
        void build(){
            node[0].fail = -1;
            q.push(0);
    
            while(!q.empty()){
                int u = q.front();
                q.pop();
                if(node[node[u].fail].cnt && u) node[u].cnt = 1;   //都不能取
                for(int i = 0; i < 4; i++){
                    if(!node[u].next[i]){
                        if(u == 0)
                            node[u].next[i] = 0;
                        else
                            node[u].next[i] = node[node[u].fail].next[i];
                    }
                    else{
                        if(u == 0) node[node[u].next[i]].fail = 0;
                        else{
                            int v = node[u].fail;
                            while(v != -1){
                                if(node[v].next[i]){
                                    node[node[u].next[i]].fail = node[v].next[i];
                                    break;
                                }
                                v = node[v].fail;
                            }
                            if(v == -1) node[node[u].next[i]].fail = 0;
                        }
                        q.push(node[u].next[i]);
                    }
                }
            }
        }
    
        void query(){
            Mat a;
            memset(a.s, 0, sizeof(a.s));
            for(int i = 0; i < size; i++){
                for(int j = 0; j < 4; j++){
                    if(node[node[i].next[j]].cnt == 0){
                        a.s[i][node[i].next[j]]++;
                    }
                }
            }
            a = ppow(a, n);
            ll ans = 0;
            for(int i = 0; i < size; i++){
                if(node[i].cnt == 0) ans = (ans + a.s[0][i]) % MOD;
            }
            printf("%lld
    ", ans);
        }
    
    }ac;
    char s[20];
    int main(){
        while(~scanf("%d%lld", &m, &n)){
            ac.init();
            while(m--){
    
                scanf("%s", s);
                ac.insert(s);
            }
            ac.build();
            tn = ac.size;
            ac.query();
        }
        return 0;
    }
  • 相关阅读:
    金融理财
    股权穿透图资料总结
    v-cloak指令用法
    前端跨域解决方案
    better-scroll
    vant-list实现下拉加载更多
    webpack原理
    .NET Framwork WebApi 添加swagger 在线接口文档步骤
    CORE API 限流,防止,链接数过多而崩溃。
    VS2019推送代码到GIT仓库
  • 原文地址:https://www.cnblogs.com/KirinSB/p/11180526.html
Copyright © 2020-2023  润新知