AC自动机专题——G - DNA Sequence POJ - 2778 矩阵快速幂+AC自动机

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



题目思路:

其与E、F题类似,都是求给定长度不含某些序列的数量。

不过这里有一个特点就是其字符串长度很长,肯定无法用DP来做,

类比一下,其答案就是在一个图上有多少条长度为N的路径,这里就想到了通过矩阵快速幂的log(n)的时间复杂度来做。


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <climits>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <list>
#define rep(i,m,n) for(int i=m;i<=n;i++)
#define rsp(it,s) for(set<int>::iterator it=s.begin();it!=s.end();it++)
const int inf_int = 2e9;
const long long inf_ll = 2e18;
#define inf_add 0x3f3f3f3f
#define MOD 100000
#define pb push_back
//#define mp make_pair
#define fi first
#define se second
#define pi acos(-1.0)
#define pii pair<int,int>
#define Lson L, mid, rt<<1
#define Rson mid+1, R, rt<<1|1
const int maxn=5e2+10;
using namespace std;
typedef  vector<int> vi;
typedef  long long ll;
typedef  unsigned long long  ull;
inline int read(){int ra,fh;char rx;rx=getchar(),ra=0,fh=1;
while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();if(rx=='-')
fh=-1,rx=getchar();while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,
rx=getchar();return ra*fh;}
//#pragma comment(linker, "/STACK:102400000,102400000")
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p;p=p*p;q>>=1;}return f;}


int dir[8][2]={{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};

map<char, int> mp;


struct Matrix
{
    unsigned long long mat[110][110];
    int n;
    Matrix(){}
    Matrix(int _n)
    {
        n=_n;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                mat[i][j] = 0;
    }
    Matrix operator *(const Matrix &b)const
    {
        Matrix ret = Matrix(n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                {
                    ret.mat[i][j]=(ret.mat[i][j]+mat[i][k]*b.mat[k][j]) % MOD;
                }


        return ret;
    }
};


unsigned long long pow_m(unsigned long long a,int n)
{
    unsigned long long ret=1;
    unsigned long long tmp = a;
    while(n)
    {
        if(n&1)ret*=tmp;
        tmp*=tmp;
        n>>=1;
    }
    return ret;
}


Matrix pow_M(Matrix a,int n)
{
    Matrix ret = Matrix(a.n);
    for(int i=0;i<a.n;i++)
        ret.mat[i][i] = 1;
    Matrix tmp = a;
    while(n)
    {
        if(n&1)ret=ret*tmp;
        tmp=tmp*tmp;
        n>>=1;
    }
    return ret;
}



const int N = 1005;
const int M = 51;

class Trie
{

public:
    int next[N][M],fail[N],end[N];
    int root,L;
    int newnode()
    {
        for(int i = 0;i < M;i++)//每一个节点对应0-128中的任意一个。
            next[L][i] = -1;
        end[L++] = -1;//表示下面没有节点 初始化,如果是记录次数,就赋0 还可以赋任意的数,
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(char s[])
    {
        int len = strlen(s);
        int now = root;
        for(int i = 0;i < len;i++)
        {
            if(next[now][mp[s[i]]] == -1)
                next[now][mp[s[i]]] = newnode();
            now=next[now][mp[s[i]]];//记录其对应的节点编号
        }
        end[now]=1;//记录当前匹配单词的节点
        //end[now]++;也可以用匹配单词结束后来记录次数
    }
    void build()
    {
        queue<int>Q;
        fail[root] = root;//根节点仍然是根节点
        for(int i = 0;i < M;i++)//对第一个字符遍历
            if(next[root][i] == -1)//没有此字符开头
                next[root][i] = root;//跳转到根
            else//有此字符开头的
            {
                fail[next[root][i]] = root;//这个行位的失败指针为根
                Q.push(next[root][i]);//行放入队列
            }
        while(!Q.empty())//还有字符
        {
            int now = Q.front();//逐层拿出第一个
            Q.pop();
            if(end[fail[now]]== 1) end[now] = 1;
            for(int i = 0;i < M;i++)//对这一行
                if(next[now][i] == -1)//如果下一行没有这个字符
                    next[now][i] = next[fail[now]][i];//他的下一个的这
                else//如果有这个字符
                {
                    fail[next[now][i]] = next[fail[now]][i];//他的下一个的
                    Q.push(next[now][i]);//下一行继续
                }
        }
    }


    /*bool used[N];//判断其是否被查找到
    bool query(char buf[],int n,int id)
    {
        int len = strlen(buf);
        int now = root;
        memset(used,false,sizeof(used));//初始化used
        bool flag = false;
        for(int i = 0;i < len;i++)
        {
            now = next[now][buf[i]];
            int temp = now;
            while(temp != root)
            {
                if(end[temp] != -1)
                {
                    used[end[temp]] = true;//记录被匹配的信息
                    flag = true;
                }
                temp = fail[temp];
            }
        }

    }*/
    Matrix getMatrix()
    {
        Matrix ret = Matrix(L+1);
        for(int i = 0;i < L;i++)
        {
            if(end[i]==1) continue;
            for(int j = 0;j < 4;j++)
            {
                if(end[next[i][j]]==1) continue;
                ret.mat[i][next[i][j]] ++;
            }
        }
        return ret;
    }
};

char buf[10005];
int m,p;
Trie ac;


int main()
{
    mp.clear();
    mp['A'] = 0;
    mp['C'] = 1;
    mp['T'] = 2;
    mp['G'] = 3;
    while(~scanf("%d %d",&p,&m))
    {
        ac.init();
        while(p--)
        {
            scanf("%s", buf);
            ac.insert(buf);
        }
        ac.build();
        Matrix E = ac.getMatrix();
        Matrix ans = pow_M(E,m);
        int number = 0;
        for(int i = 0;i < ac.L;i++){
            number += ans.mat[0][i];
            number %= MOD;
        }
        printf("%d\n",number);
    }
    return 0;
}







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值