ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【POJ-2778】DNA Sequence(DP转移+矩阵快速幂+AC自动机)

2020-11-16 20:33:06  阅读:157  来源: 互联网

标签:2778 AC DNA mat int ++ const now


题目连接:https://vjudge.net/problem/POJ-2778

题目大意

给定 \(m\) 个字符串,问构造一个长度为 \(n\) 的字符串,使其不含 \(m\) 个字符串,问构造方法种类。

思路

AC自动机和矩阵快速幂部分这篇博客已经说的很好了,个人主要是 AC自动机病毒后缀的转移DP递推式 卡了很久。

首先是AC自动机上病毒后缀的转移,AC自动机的fail指针指向的是指以节点 \(x\) 结尾的文本串在其他模式串中所能匹配的最长前缀的地方。

若其fail指针所指向的地方为 \(m\)个字符串的结尾,那么其也不可达,在 \(build\) 时能够保证顺序。

然后是DP递推式,设 \(dp[i][j]\) 为走了\(j\) 步到达节点 \(i\) 的方案数,显然 \(dp[0][0]=1\),当 \(i \neq 0\) 时,\(dp[i][0]=0\)。

设 \(a[i][j]\) 为从节点 \(i\) 到达节点 \(j\) 是否存在边。

最终得 \(dp[i][j] = \sum_{x=0}^{N} a[x][i] * dp[x][j-1]\),这部分可以用矩阵快速幂解决。

AC代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>

typedef long long ll;
using namespace std;

const int MAXN = 1e6 + 5;
const int MAXM = 110;
const int mod = 100000;

class mat {
public:
    int n, m;
    int v[MAXM][MAXM];

    mat(int n, int m) : n(n), m(m) {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++)
                v[i][j] = 0;
        }
    }

    void init() {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++)
                v[i][j] = 0;
        }
    }

    void init1() {
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                v[i][j] = (i == j); //单位矩阵
    }

    mat operator*(const mat &B) const {//矩阵乘法 A(n,k)*B(k,m)=C(n,m);
        mat C(n, B.m);
        C.init();
        for (int i = 0; i < n; i++)
            for (int j = 0; j < B.m; j++)
                for (int k = 0; k < m; k++)
                    C.v[i][j] = (C.v[i][j] + (ll) v[i][k] * B.v[k][j] % mod) % mod;//Mod
        return C;
    }

    mat operator^(int t) {//矩阵快速幂 n=m时可用
        mat ans(n, n), now(n, n);
        ans.init1();
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                now.v[i][j] = v[i][j];
        while (t > 0) {
            if (t & 1) ans = ans * now;
            now = now * now;
            t >>= 1;
        }
        return ans;
    }

    void debug() {
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= n; j++) {
                printf("%d ", v[i][j]);
            }
            printf("\n");
        }
    }

};


int char2id(char ch) {
    switch (ch) {
        case 'A':
            return 0;
        case 'T':
            return 1;
        case 'G':
            return 2;
        case 'C':
            return 3;
    }
}

class AC {
public:
    int T[MAXN][4], top;
    bool endpos[MAXN];
    int fail[MAXN];
    queue<int> q;

    void init() {
        top = 1;
        memset(T[0], 0, sizeof(T[0]));
        endpos[0] = fail[0] = 0;
    }

    void insert(char str[], int lenstr) {
        int u = 0;
        for (int i = 1; i <= lenstr; i++) {
            int ch = char2id(str[i]);
            if (!T[u][ch]) {
                endpos[top] = fail[top] = 0;    // init a node
                memset(T[top], 0, sizeof(T[top]));
                T[u][ch] = top++;
            }
            u = T[u][ch];
        }
        endpos[u] = 1;
    }

    void build() {
        for (int i = 0; i < 4; i++)
            if (T[0][i]) {
                fail[T[0][i]] = 0;
                q.push(T[0][i]);
            }
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            if (endpos[fail[u]]) endpos[u] = 1;
            for (int i = 0; i < 4; i++)
                if (T[u][i]) {
                    fail[T[u][i]] = T[fail[u]][i];
                    q.push(T[u][i]);
                } else T[u][i] = T[fail[u]][i];
        }
    }

    void build_mat(mat &mat) {
        mat.init();
        for (int i = 0; i < top; i++) {
            if (endpos[i]) continue;
            for (int j = 0; j < 4; j++) {
                if (!endpos[T[i][j]]) mat.v[i][T[i][j]]++;
            }
        }
    }

} ac;

char str[MAXN];


int main() {

    int m, n;
    while (~scanf("%d%d", &m, &n)) {
        ac.init();
        while (m--) {
            scanf("%s", str + 1);
            ac.insert(str, strlen(str + 1));

        }
        ac.build();


        mat ma(ac.top, ac.top);
        ac.build_mat(ma);

        ma = ma ^ n;
        int res = 0;
        for (int i = 0; i < ac.top; i++) {
            res = (res + ma.v[0][i]) % mod;
        }
        printf("%d\n", res);
    }
}

/*
2 10
AG
CG
 */

标签:2778,AC,DNA,mat,int,++,const,now
来源: https://www.cnblogs.com/tudouuuuu/p/13986981.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有