POJ 2778(AC自动机+矩阵快速幂)

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

题目大意:给出n个病毒串,问长度为m的DNA序列中有多少种是不包含病毒串的。

解题思路:我们将病毒串加入AC自动机中,然后我们先创建一个矩阵表示从i点走到j点的长度为1的字符串中不包含病毒串的种类数。我们知道,如果从i点到j点的长度为2的字符串可以由从i点到k点长度为1的字符串和从k点到j点长度为1的字符串拼接得到,所以其实我们列出来所有的k就可以看出这是一个矩阵乘法公式。所以我们将这个矩阵乘以m次就可以啦。然后计算从0点到其他点的种类数。

代码:

#pragma GCC optimize(2)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <bitset>
#include <queue>
//#include <random>
#include <time.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define ls root<<1
#define rs root<<1|1
const int inf=1ll*1<<60;
const int maxn=1e4+10;
const int maxm=1e6+10;
const int mod=100000;
char arr[110];
int trie[110][4],fail[110],tot,val[110],idx[128];
void add(char *s)
{
    int now=0;
    for(int i=0;s[i]!='\0';i++){
        int x=idx[s[i]];
        if(!trie[now][x]) trie[now][x]=++tot;
        now=trie[now][x];
    }
    val[now]=1;
}
void getfail()
{
    queue<int> q;
    for(int i=0;i<4;i++)
        if(trie[0][i])q.push(trie[0][i]);
    while(!q.empty()){
        int now=q.front();q.pop();
        for(int i=0;i<4;i++){
            if(trie[now][i]){
                fail[trie[now][i]]=trie[fail[now]][i];
                q.push(trie[now][i]);
            }
            else trie[now][i]=trie[fail[now]][i];
            val[trie[now][i]]|=val[trie[fail[now]][i]];
        }
    }
}
struct martix
{
    int mat[110][110];
    martix(){
        memset(mat,0,sizeof mat);
    }
};
martix operator *(const martix a,const martix b)
{
    martix z;
    for(int i=0;i<=tot;i++){
        for(int j=0;j<=tot;j++){
            for(int k=0;k<=tot;k++){
                z.mat[i][j]+=a.mat[i][k]*b.mat[k][j];
                z.mat[i][j]%=mod;
            }
        }
    }
    return z;
}
signed main()
{
    int n,m;
    scanf("%lld%lld",&n,&m);
    idx['A']=0,idx['C']=1,idx['G']=2,idx['T']=3;
    for(int i=0;i<n;i++){
        scanf("%s",arr);
        add(arr);
    }
    getfail();
    martix e,x;
    for(int i=0;i<=tot;i++){
        e.mat[i][i]=1;
    }
    for(int i=0;i<=tot;i++){
        if(val[i])continue;
        for(int j=0;j<4;j++){
            if(val[trie[i][j]])continue;
            x.mat[i][trie[i][j]]++;
        }
    }
    while(m){
        if(m&1)e=e*x;
        x=x*x;
        m>>=1;
    }
    int ans=0;
    for(int i=0;i<=tot;i++){
        ans+=e.mat[0][i];
        ans%=mod;
    }
    printf("%lld\n",ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值