E - DNA Sequence POJ - 2778

It’s well known that DNA Sequence is a sequence only contains A, C, T and G, and it’s very useful to analyze a segment of DNA Sequence,For example, if a animal’s DNA sequence contains segment ATC then it may mean that the animal may have a genetic disease. Until now scientists have found several those segments, the problem is how many kinds of DNA sequences of a species don’t contain those segments.

Suppose that DNA sequences of a species is a sequence that consist of A, C, T and G,and the length of sequences is a given integer n.
Input
First line contains two integer m (0 <= m <= 10), n (1 <= n <=2000000000). Here, m is the number of genetic disease segment, and n is the length of sequences.

Next m lines each line contain a DNA genetic disease segment, and length of these segments is not larger than 10.
Output
An integer, the number of DNA sequences, mod 100000.
Sample Input
4 3
AT
AC
AG
AA
Sample Output
36

说实话这题想的我真是着急了,首先感觉tires树上建立矩阵求幂,这简直不存在的好吗(担心的是是否存在重复串问题),现在终于想通了,说一下自己的分析,不关心病毒串,要求n长度的串的个数,则实际上这可以看作是一棵树,树有n+1层,第一层根节点为空字符串,第二层由根节点指向ATGC,共4个结点,以此类推,于是第n+1层的结点个数即为所求,但事实上,我们不需要建立这么大的一颗树,而是可以建立一个图,此时考虑病毒串,由于病毒串不可取,于是tries树中从一些结点开始不需要再往下延伸了,其次,我们可以把一些结点进行压缩,比方说样例的AT,AC,AG,AA可如下图一样建图。
这里写图片描述
可以看到A的AGTC由于取不了就将A指向根节点,GTC由于不会包含病毒串,于是可指向根节点,实际上这是可以根据AC自动机来实现这样的建图的,像之前说的,事实上这就是一个向下不断延伸的过程,于是这实际上就相当于总的方案数就是根节点走n步到其他已有结点的方案数(在跑AC自动机的时候事实上会将GTC这三个结点也省去,可以想想这三个结点走的方法到哪去了)而一个图中从i走到j走n步的方法数可根据邻接矩阵求幂得到,二分即可求解。
贴代码:

#include <iostream>
#include <string>
#include <set>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <queue>
#include <cstring>
#include <stack>
using namespace std;
#define ll long long
#define mod 100000
int m, n, ch[105][5], val[105], f[105], sz; //last[105];
char str[15];
struct matrix {
    ll a[105][105];
    void init() {
        memset(a, 0, sizeof(a));
    }
};
matrix mutimatrix(matrix& a, matrix& b) {
    matrix c;
    c.init();
    for (int i = 0; i < sz; ++i) {
        for (int j = 0; j < sz; ++j) {
            for (int k = 0; k < sz; ++k) {
                c.a[i][j] += a.a[i][k] * b.a[k][j];
                if (c.a[i][j] > mod) {
                    c.a[i][j] %= mod;
                }
            }
        }
    }
    return c;
}
int getnum(char ch) {
    if (ch == 'A') return 0;
    else if (ch == 'G') return 1;
    else if (ch == 'T') return 2;
    else return 3;
}
void insert() {
    int u = 0;
    for (int i = 0; str[i] != '\0'; ++i) {
        int t = getnum(str[i]);
        if (!ch[u][t]) {
            memset(ch[sz], 0, sizeof(ch[sz]));
            val[sz] = 0;
            ch[u][t] = sz++;
        }
        u = ch[u][t];
    }
    val[u] = 1;
}
void getfail() {
    int u = 0;
    f[u] = 0;
    queue<int> q;
    for (int i = 0; i < 4; ++i) {
        int t = ch[u][i];
        if (t) {
            q.push(t);
            f[t] = 0;
        }
    }
    while (!q.empty()) {
        u = q.front();
        q.pop();
        for (int i = 0; i < 4; ++i) {
            int t = ch[u][i];
            if (!t) {
                ch[u][i] = ch[f[u]][i];
                continue;
            }
            q.push(t);
            int v = f[u];
            while (v && !ch[v][i]) {
                v = f[v];
            }
            f[t] = ch[v][i];
            val[t] |= val[f[t]];
        }
    }
}
void solve() {
    matrix A;
    A.init();
    for (int i = 0; i < sz; ++i) {
        if (val[i]) {
            continue;
        }
        for (int j = 0; j < 4; ++j) {
            int t = ch[i][j];
            if(!val[t])
                A.a[i][t]++;
        }
    }
    matrix ans;
    ans.init();
    for (int i = 0; i < sz; ++i) {
        ans.a[i][i] = 1;
    }
    while (n) {
        if (n & 1) {
            ans = mutimatrix(ans, A);
        }
        A = mutimatrix(A, A);
        n >>= 1;
    }
    ll sum = 0;
    for (int i = 0; i < sz; ++i) {
        sum = sum + ans.a[0][i];
        if (sum > mod) {
            sum %= mod;
        }
    }
    printf("%lld\n", sum);
}
int main() {
    while (~scanf("%d%d", &m, &n)) {
        sz = 1;
        memset(ch[0], 0, sizeof(ch[0]));
        for (int i = 0; i < m; ++i) {
            scanf("%s", str);
            insert();
        }
        getfail();
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值