poj2778 DNA Sequence

本文介绍了一道关于DNA序列分析的问题,通过构建Trie树和AC自动机解决特定长度DNA序列中不包含已知疾病相关片段的数量计算。文章提供了完整的代码实现。

DNA Sequence

Description

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

题目大意

给出m种DNA序列是有疾病的,问有多少种长度为n的DNA序列不包含任何一种有疾病的DNA序列。(仅含A,T,C,G四个字符)

题解

首先以所有疾病序列为模板串构建Trie树和AC自动机的fail指针。将序列末尾节点设置为危险点,而fail指针指向的点是危险点的点也设置为危险点。在建好的Trie树中删去所有的危险点。不难想到在这棵Trie树上从0节点开始走n步有多少种走法,答案即为多少。
考虑建造一个矩阵mat,mat[i][j] 表示从i节点1步走到j节点有多少种方案。那么 matn 即为答案。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<memory>
#include<vector>
#include<deque>
#include<cmath>
#include<ctime>
#include<queue>
#include<list>
#include<map>
#include<set>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define F(i,j,n) for(register int i=j;i<=n;i++)
#define D(i,j,n) for(register int i=j;i>=n;i--)
#define ll long long
#define db double
using namespace std;

inline void in(int &x);
inline void in(ll &x);

const int mod = 100000, max_size = 100 + 10, ch_size = 4;
int m, n;
char s[20];

struct Matrix{
    int p, q;
    ll mat[max_size][max_size];
    Matrix(){memset(mat, 0, sizeof(mat));}
}m1;
Matrix operator *(Matrix m1, Matrix m2){
    Matrix m3;
    m3.p = m1.p; m3.q = m2.q;
    for(int i = 0; i < m3.p; i++)
    for(int j = 0; j < m3.q; j++){
        int ret = 0;
        for(int k = 0; k < m1.q; k++)
            ret += (m1.mat[i][k] * m2.mat[k][j]) % mod;
        m3.mat[i][j] = ret % mod;
    }
    return m3;
}
Matrix matrix_pow(Matrix x, int y){
    Matrix res;
    res.p = x.p, res.q = x.q;
    for(int i = 0; i < res.p; i++)
        for(int j = 0; j < res.q; j++)
            res.mat[i][j] = m1.mat[i][j];
    while(y){
        if (y & 1) res = res * x;
        x = x * x;
        y >>= 1;
    }
    return res;
}
struct Trie{
    int ch[max_size][ch_size];
    int val[max_size], f[max_size];
    int sz;
    int idx[200];
    Trie(){sz = 1; idx['A'] = 0; idx['G'] = 1; idx['C'] = 2; idx['T'] = 3;}

    void insert(char *s){
        int u = 0, len = strlen(s);
        for(int i = 0; i < len; i++){
            int x = idx[s[i]];
            if(!ch[u][x]){
                ch[u][x] = sz++;
                val[sz] = 0;
            }
            u = ch[u][x];
        }
        val[u] = 1;
    }

    void get_fail(){
        queue<int> q;
        f[0] = 0;
        for(int i = 0; i < ch_size; i++){
            int u = ch[0][i];
            if(u){
                f[u] = 0;
                q.push(u);
            }
        }
        while(!q.empty()){
            int r = q.front(); q.pop();
            if(val[f[r]]) val[r] = 1;
            for(int i = 0; i < ch_size; i++){
                int &u = ch[r][i];
                if(!u){
                    u = ch[f[r]][i];
                    continue;
                }
                q.push(u);
                f[u] = ch[f[r]][i];
            }
        }
    }

    void build(){
        m1.p = m1.q = sz;
        for(int i = 0; i < sz; i++)
            for(int j = 0; j < ch_size; j++)
                if(!val[i] && !val[ch[i][j]])
                    m1.mat[i][ch[i][j]]++;
    }
}ac;

void init(){
    scanf("%d%d", &m, &n);
    for(int i = 1; i <= m; i++){
        scanf("%s", s);
        ac.insert(s);
    }
}
void work(){
    ac.get_fail();
    ac.build();
    m1 = matrix_pow(m1, n-1);
    int ans = 0;
    for(int i = 0; i < m1.p; i++)
        ans += m1.mat[0][i];
    printf("%d\n", ans % mod);
}

int main(){
    freopen("poj2778.in", "r", stdin);
    freopen("poj2778.out", "w", stdout);
    init();
    work();
    return 0;
}
inline void in(int &x){
    x = 0; int f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x*10 + ch - '0'; ch = getchar();}
    x *= f;
}
inline void in(ll &x){
    x = 0; ll f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x*10 + ch - '0'; ch = getchar();}
    x *= f;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值