poj2778--DNA Sequence(AC自动机+矩阵优化)

DNA Sequence

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 12252   Accepted: 4661

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

给出患病的DNA序列,问序列长度为n的,且不包含患病的DNA序列有多少种。

首先处理患病的DNA串,连接为字典树后,添加fail指针,完成AC自动机,给每个节点一个编号,然后用矩阵统计每个节点走一步可以走到的节点的种数,其中,不能包含会患病的序列,最后矩阵相乘。

注意1.__int64 相乘会超出范围。

注意2.处理自动机时,注意,如果发现某个节点的fail会返回到一个代表序列结束的节点上,那么这个节点也是不可达的。不能被统计到矩阵中。

注意3.矩阵快速幂要写成非递归的形式。

给出测试案例:

2 1

ACG

C

其中矩阵应该为

2 1 0 0 0

2 1 0 0 0

0 0 0 0 0

0 0 0 0 0

0 0 0 0 0

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std ;
#define MOD 100000
#define LL __int64
struct node{
    int flag , id ;
    node *next[4] , *fail ;
};
struct nnode{
    LL Map[110][110] , n ;
};
queue <node*> que ;
char c[5] = "ACGT" ;
char str[20] ;
int num , vis[110] ;
node *newnode()
{
    node *p = new node ;
    p->flag = 0 ;
    p->id = num++ ;
    p->fail = NULL ;
    for(int i = 0 ; i < 4 ; i++)
        p->next[i] = NULL ;
    return p ;
}
void settree(char *s,node *rt,int temp)
{
    int i , k , l = strlen(s) ;
    node *p = rt ;
    for(i = 0 ; i < l ; i++)
    {
        for(k = 0 ; k < 4 ; k++)
            if( s[i] == c[k] )
                break ;
        if( p->next[k] == NULL )
            p->next[k] = newnode() ;
        p = p->next[k] ;
    }
    p->flag = 1 ;
    return ;
}
void setfail(node *rt)
{
    int i ;
    node *p = rt , *temp ;
    p->fail = NULL ;
    while( !que.empty() ) que.pop() ;
    que.push(p) ;
    while( !que.empty() )
    {
        p = que.front() ;
        que.pop() ;
        for(i = 0 ; i < 4 ; i++)
        {
            if( p->next[i] )
            {
                temp = p->fail ;
                while( temp && !temp->next[i] )
                    temp = temp->fail ;
                p->next[i]->fail = temp ? temp->next[i] : rt ;
                if( temp != NULL && temp->next[i]->flag )
                    p->next[i]->flag = 1 ;
                que.push(p->next[i]) ;
            }
            else
                p->next[i] = p == rt ? rt : p->fail->next[i] ;
        }
    }
}
nnode setmat(node *rt)
{
    int i , j , u , v ;
    nnode q ;
    node *p = rt ;
    while( !que.empty() ) que.pop() ;
    memset(q.Map,0,sizeof(q.Map)) ;
    memset(vis,0,sizeof(vis)) ;
    que.push(p) ;
    q.n = num ;
    vis[ p->id ] = 1 ;
    while( !que.empty() )
    {
        p = que.front() ;
        que.pop() ;
        u = p->id ;
        for(i = 0 ; i < 4 ; i++)
        {
            if( !p->flag && !p->next[i]->flag )
                q.Map[ p->id ][ p->next[i]->id ]++ ;
            if( !vis[p->next[i]->id] )
            {
                vis[ p->next[i]->id ] = 1 ;
                que.push( p->next[i] ) ;
            }
        }
    }
    return q ;
}
nnode mul(nnode a,nnode b)
{
    nnode c ;
    c.n  = a.n ;
    int i , j , k ;
    for(i = 0 ; i < a.n ; i++)
    {
        for(j = 0 ; j < a.n ; j++)
        {
            c.Map[i][j] = 0 ;
            for(k = 0 ; k < a.n ; k++)
                c.Map[i][j] = ( c.Map[i][j] + a.Map[i][k]*b.Map[k][j] ) % MOD ;
        }
    }
    return c ;
}
nnode pow(nnode p,int k)
{
    nnode temp ;
    int i , j ;
    temp.n = p.n ;
    memset(temp.Map,0,sizeof(temp.Map)) ;
    for(i = 0 ; i < p.n ; i++)
        temp.Map[i][i] = 1 ;
    while( k )
    {
        if( k&1 )
            temp = mul(temp,p) ;
        p = mul(p,p) ;
        k >>= 1 ;
    }
    return temp ;
}
int main()
{
    int n , m , i , j ;
    node *rt ;
    nnode p ;
    while( scanf("%d %d", &m, &n) != EOF )
    {
        num = 0 ;
        rt = newnode() ;
        for(i = 1 ; i <= m ; i++)
        {
            scanf("%s", str) ;
            settree(str,rt,i) ;
        }
        setfail(rt) ;
        p = setmat(rt) ;
        /*for(i = 0 ; i < p.n ; i++)
        {
            for(j = 0 ; j < p.n ; j++)
                printf("%d ", p.Map[i][j]) ;
            printf("\n") ;
        }*/
        p = pow(p,n) ;
        LL ans = 0 ;
        for(i = 0 ; i < p.n ; i++)
            ans = ( ans + p.Map[0][i] ) % MOD ;
        printf("%d\n", ans) ;
    }
    return 0 ;
}

时间: 2024-11-13 22:44:50

poj2778--DNA Sequence(AC自动机+矩阵优化)的相关文章

[poj2778]DNA Sequence(AC自动机+矩阵快速幂)

解题关键:卡时限过的,正在找原因中. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstring> 6 #include<iostream> 7 #include<queue> 8 using namespace std; 9 typedef long long ll; 10 cons

POJ POJ 2778 DNA Sequence AC自动机 + 矩阵快速幂

首先建立Trie和失败指针,然后你会发现对于每个节点 i 匹配AGCT时只有以下几种情况: i 节点有关于当前字符的儿子节点 j 且安全,则i 到 j找到一条长度为 1的路. i 节点有关于当前字符的儿子节点 j 且 不安全,则i 到 j没有路. i 节点没有关于当前字符的儿子节点 但是能通过失败指针找到一个安全的节点j,那么 i 到 j 找到一条长度为1的路. 关于节点安全的定义: 当前节点不是末节点且当前节点由失败指针指回跟节点的路径上不存在不安全节点,那么这个节点就是安全节点. 然后问题就

poj 2778 DNA Sequence(AC自动机+矩阵快速幂)

题目链接:poj 2778 DNA Sequence 题目大意:给定一些含有疾病的DNA序列,现在给定DNA长度,问有多少种不同的DNA序列是健康的. 解题思路:对DNA片段建立AC自动机,因为最多10个串,每个串最长为10,所以最多可能有100个节点,在长度为n时 以每个节点终止的健康字符串个数形成一个状态集,通过AC自动机形成的边可以推导出n+1的状态集,走到单词节点是 非法的,所以同样的我们可以先走到单词节点,但是从单词节点不向后转移.这样可以构造一个矩阵,剩下的就是矩阵 快速幂.注意的一

POJ 2778 DNA Sequence (AC自动机,矩阵乘法)

题意:给定n个不能出现的模式串,给定一个长度m,要求长度为m的合法串有多少种. 思路:用AC自动机,利用AC自动机上的节点做矩阵乘法. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<string> 6 #include<algorithm> 7 #include<queue> 8 #defin

Poj 2778 DNA Sequence (AC自动机+矩阵)

题目大意: 给出N个串,问在长度为L的所有串中,不包含任一已知串的个数有多少个. 思路分析: 已知一个矩阵A,A[i][j] 表示 节点i 到 节点 j 有一条变可以到达的方法数. 那么A^2 ,这个矩阵的 [i][j] 就代表这个节点 i 到节点 j 有两条边可以到达的方法数. 那么知道这个结论,我们要做的就是求一个节点到另外一个节点,要经过L条变(对应这长度为L的单词),而又要满足任意一条边都不能经过已知单词. 所以我们要用到ac自动机处理出所有已知的单词,在ac自动机上得到这个矩阵,使得任

POJ2778---DNA Sequence(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

poj2778DNA Sequence (AC自动机+矩阵快速幂)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud DNA Sequence Time Limit: 1000MS   Memory Limit: 65536K 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 DN

AC自动机 + 矩阵优化 --- [BJOI2017]魔法咒语

bzoj 4860   LOJ2180   洛谷P3175 [BJOI2017]魔法咒语 题目描述: Chandra 是一个魔法天才. 从一岁时接受火之教会洗礼之后,Chandra 就显示出对火元素无与伦比的亲和力,轻而易举地学会种种晦涩难解的法术. 这也多亏 Chandra 有着常人难以企及的语言天赋,让她能轻松流利地说出咒语中那些极其拗口的魔法词汇. 直到十四岁,开始学习威力强大的禁咒法术时,Chandra 才遇到了障碍. 根据火之魔法规则,禁咒的构成单位是 N 个基本词汇. 施法时只要凝聚

AC自动机 + 矩阵优化 + 期望 --- [BJOI2011]禁忌

bzoj 2553 [BJOI2011]禁忌 题目描述: Magic Land上的人们总是提起那个传说:他们的祖先John在那个东方岛屿帮助Koishi与其姐姐Satori最终战平.而后,Koishi恢复了读心的能力-- 如今,在John已经成为传说的时代,再次造访那座岛屿的人们却发现Koishi遇到了新麻烦. 这次她遇到了Flandre Scarlet--她拥有可以使用禁忌魔法而不会受到伤害的能力. 为了说明什么是禁忌魔法及其伤害,引入以下概念: 1.字母集A上的每个非空字符串对应了一个魔法.