【POJ2778】【AC自动机】【矩阵快速幂】17.2.9 T2 DNA Sequence 题解

DNA Sequence
基因序列可以看做是只含大写ACGT 的字符串。
现有n 个癌症序列,每个癌症序列有至多10 个字符。
现请问不含癌症序列的长度为len 的基因有多少个?答案对100000 取模。
【输入格式】
第一行两个数n, len,表示癌症序列的个数和待求基因的长度。
接下来n 行,每一行一个字符串,表示癌症序列。
【输出格式】
一个整数,表示不含癌症序列的长度为len 的基因有多少个?答案对
100000 取模。
【输入样例】
4 3
AT
AC
AG
AA
【输出样例】
36
【数据规模】
10% 数据满足len ≤ 10。
90% 数据满足len ≤ 1000
100% 数据满足0 ≤ n ≤ 10, 1 ≤ len ≤ 2000000000

将题目简化,只有4个字母,给出模板串,求规定长度内的单词有多少不含模板串

这里写图片描述

建立trie的邻接矩阵M
M[i][j]表示i到j只走一步的走法
M的n次幂就是i到j走n步有多少种走法

删除癌症序列结点所在的行和列
将单词结尾(即癌症序列结尾)与fail直接指向癌症序列的节点删除

计算M的n次幂,ans=Σ(M[0,i])%100000

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string>
#include <iomanip>
#include <ctime>
#include <climits>
#include <cctype>
#include <algorithm>
#define clr(x) memset(x,0,sizeof(x))
#define LL long long
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif

using namespace std;

const int MOD = 100000;
const int maxn = 105;
const int kind = 4;
typedef LL M[maxn][maxn];
M mat,mat1,mat2;
LL (*m1)[maxn],(*m2)[maxn];

class AC_DFA {
    public:
        int n,id['Z'+1],fail[maxn],trie[maxn][kind];
        bool tip[maxn];

        void makeID() { id['A'] = 0; id['T'] = 1; id['C'] = 2; id['G'] = 3; }

        void reset() {
            memset(trie[0], -1, sizeof(trie[0]));
            tip[0] = false; n = 1;
        }

        void add(char *s) {
            int p = 0;
            while(*s) {
                int i = id[*s];
                if(trie[p][i] == -1) {
                    memset(trie[n], -1, sizeof(trie[n]));
                    tip[n] = false;
                    trie[p][i] = n++;
                }
                p = trie[p][i];
                s++;
            }
            tip[p] = true;
        }

        void setfail() {
            queue<int> Q;
            fail[0] = 0;
            for(int i = 0; i < kind; i++)
                if(-1 != trie[0][i]) fail[trie[0][i]] = 0, Q.push(trie[0][i]);
                else trie[0][i] = 0;
            while(!Q.empty()) {
                int u = Q.front();
                Q.pop();
                if(tip[fail[u]]) tip[u] = true;
                for(int i = 0; i < kind; i++) {
                    int &v = trie[u][i];
                    if(v != -1) Q.push(v), fail[v] = trie[fail[u]][i];
                    else v = trie[fail[u]][i];
                }
            }
        }

        void build() {
            clr(mat);
            for(int i = 0; i < n; i++)
                for(int j = 0; j < kind; j++)
                    if(!tip[i] && !tip[trie[i][j]]) mat[i][trie[i][j]]++;
        }
}AC;

void mult(M t1, M t2, M r)
{
    for(int i = 0; i < AC.n; i++)
        for(int j = 0; j < AC.n; j++)
        {
            r[i][j] = 0;
            for(int k = 0; k < AC.n; k++) r[i][j] += t1[i][k] * t2[k][j];
            r[i][j] %= 100000;
        }
}

void power(int p) {                     //快速幂 
    if(p == 1) {
        for(int i = 0; i < AC.n; i++)
            for(int j = 0; j < AC.n; j++) m2[i][j] = mat[i][j];
        return;
    }
    power(p>>1);
    mult(m2, m2, m1);
    if(p%2) mult(m1, mat, m2);  
    else swap(m1, m2);
}

int main() {
    freopen("gene.in","r",stdin);
    freopen("gene.out","w",stdout);
    int n,m;
    char s[12];
    AC.makeID();
    scanf("%d%d",&m,&n);
    AC.reset();
    while(m--) scanf("%s",s), AC.add(s);
    AC.setfail(); AC.build();
    m1 = mat1; m2 = mat2;
    power(n);
    int ans = 0;
    for(int i = 0; i < AC.n; i++) ans += m2[0][i];
    printf("%d\n",ans%MOD);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值