zoukankan      html  css  js  c++  java
  • POJ 2778 DNA Sequence (矩阵快速幂 + AC自动鸡)

    题目:传送门

    题意: 给你m个病毒串,只由(A、G、T、C) 组成, 问你生成一个长度为 n 的 只由 A、C、T、G 构成的,不包含病毒串的序列的方案数。

    解: 对 m 个病毒串,建 AC 自动机, 然后, 这个AC自动机就类似于一张有向图, 可以用邻接矩阵存这张有向图。

      最多10个病毒串, 每个病毒串长度不超过 10, 那最多是个 100 * 100 的矩阵, 可以接受。

       最后用矩阵快速幂加速推导。

      

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define LL long long
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define INF 0x3f3f3f3f
    #define inf 0x3f3f3f3f3f3f3f3f
    #define mem(i, j) memset(i, j, sizeof(i))
    #define pb push_back
    using namespace std;
    
    const int N = 111, mod = 100000;
    struct mat {
        LL a[N][N];
        mat() { mem(a, 0); }
    };
    struct Trie {
        int ch[N][30], tot, metch[N], Fail[N];
        void init() {
            mem(ch[0], 0); tot = 1; metch[0] = 0;
        }
        int get(char Q) {
            if(Q == 'A') return 0;
            else if(Q == 'C') return 1;
            else if(Q == 'T') return 2;
            return 3;
        }
        void join(char s[]) {
            int now = 0; int len = strlen(s);
            rep(i, 0, len - 1) {
                int id = get(s[i]);
                if(!ch[now][id]) {
                    mem(ch[tot], 0); metch[tot] = 0;
                    ch[now][id] = tot++;
                }
                now = ch[now][id];
            }
            metch[now] = 1;
        }
        void getFail() {
            queue<int> Q; while(!Q.empty()) Q.pop();
            rep(i, 0, 3) {
                if(ch[0][i]) {
                    Q.push(ch[0][i]); Fail[ch[0][i]] = 0;
                }
            }
            while(!Q.empty()) {
                int now = Q.front(); Q.pop();
                rep(i, 0, 3) {
                    int u = ch[now][i];
                    if(u == 0) ch[now][i] = ch[Fail[now]][i];
                    else {
                        Q.push(u);
                        Fail[u] = ch[Fail[now]][i];
                        metch[u] |= metch[Fail[u]];
                    }
                }
            }
        }
        mat getMat() {
            mat A;
            rep(i, 0, tot - 1) {
                if(metch[i]) continue;
                rep(j, 0, 3) {
                    if(!metch[ch[i][j]]) A.a[i][ch[i][j]]++;
                }
            }
            return A;
        }
    };
    Trie AC;
    char b[25];
    mat mul(mat A, mat B, int n) {
        mat C;
        rep(i, 0, n) {
            rep(j, 0, n) {
                rep(k, 0, n) {
                    C.a[i][j] = (C.a[i][j] + A.a[i][k] * B.a[k][j]) % mod;
                }
            }
        }
        return C;
    }
    mat ksm(mat A, int B, int n) {
        mat res; rep(i, 0, n) res.a[i][i] = 1;
        while(B) {
            if(B & 1) res = mul(res, A, n);
            A = mul(A, A, n); B >>= 1;
        }
        return res;
    }
    int main() {
        int n, m;
        while(~scanf("%d %d", &m, &n)) {
            AC.init();
            rep(i, 1, m) {
                scanf("%s", b); AC.join(b);
            }
            AC.getFail();
            mat A; A = AC.getMat();
            mat ans = ksm(A, n, AC.tot - 1);
            LL res = 0LL;
            rep(i, 0, AC.tot - 1) {
                res = (res + ans.a[0][i]) % mod;
            }
            printf("%lld
    ", res);
        }
        return 0;
    }
    View Code
    一步一步,永不停息
  • 相关阅读:
    Chrome开发者工具中Elements(元素)断点的用途
    最简单的SAP云平台开发教程
    Java实现 LeetCode 495 提莫攻击
    Java实现 LeetCode 494 目标和
    Java实现 LeetCode 494 目标和
    Java实现 LeetCode 494 目标和
    Java实现 LeetCode 493 翻转对
    Java实现 LeetCode 493 翻转对
    Java实现 LeetCode 493 翻转对
    Java实现 LeetCode 492 构造矩形
  • 原文地址:https://www.cnblogs.com/Willems/p/12004676.html
Copyright © 2011-2022 走看看