题目:传送门

题意: 给你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\n", res);
    }
    return 0;
}
View Code
12-26 20:26