poj 2778 AC自动机与矩阵连乘

http://poj.org/problem?id=2778

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
/**
poj 2778 AC自动机与矩阵连乘
题目大意:给定一些模式串,问可以构造出多少中长度为n且不含模式串中的任何一个作为子串的字符串
解题思路:构造自动机,写出状态转移的矩阵,进行矩阵快速幂,其n次幂就表示长度为n。然后mat[0][i]就表示从根节点到状态点i长度为n的字符串有多少种
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
const int MOD=100000;
struct Matrix
{
    int mat[110][110],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++)
                {
                    int tmp=(long long)mat[i][k]*b.mat[k][j]%MOD;
                    ret.mat[i][j]=(ret.mat[i][j]+tmp)%MOD;
                }
            }
        }
        return ret;
    }
};

struct Trie
{
    int next[110][4],fail[110],end[110];
    int root,L;
    int newnode()
    {
        for(int i=0; i<4; i++)
            next[L][i]=-1;
        end[L++]=0;
        return L-1;
    }
    void init()
    {
        L=0;
        root=newnode();
    }
    int getch(char ch)
    {
        if(ch=='A')
            return 0;
        if(ch=='C')
            return 1;
        if(ch=='G')
            return 2;
        return 3;
    }
    void insert(char *s)
    {
        int len=strlen(s);
        int now=root;
        for(int i=0; i<len; i++)
        {
            if(next[now][getch(s[i])]==-1)
                next[now][getch(s[i])]=newnode();
            now=next[now][getch(s[i])];
        }
        end[now]=1;
    }
    void build()
    {
        queue <int>Q;
        for(int i=0; i<4; 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<4; 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]);
                }
            }
        }
    }
    Matrix getMatrix()
    {
        Matrix res=Matrix(L);
        for(int i=0; i<L; i++)
        {
            for(int j=0; j<4; j++)
            {
                if(end[next[i][j]]==0)
                    res.mat[i][next[i][j]]++;
            }
        }
        return res;
    }
} ac;
char buf[20];

Matrix pow_M(Matrix a,int n)
{
    Matrix ret=Matrix(a.n);
    for(int i=0; i<ret.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;
}

int main()
{
     int n,m;
     while(~scanf("%d%d",&n,&m))
     {
         ac.init();
         for(int i=0;i<n;i++)
         {
             scanf("%s",buf);
             ac.insert(buf);
         }
         ac.build();
         Matrix a=ac.getMatrix();
         a=pow_M(a,m);
         int ans=0;
         for(int i=0;i<a.n;i++)
         {
             ans=(ans+a.mat[0][i])%MOD;
         }
         printf("%d\n",ans);
     }
     return 0;
}

时间: 2024-12-17 05:32:57

poj 2778 AC自动机与矩阵连乘的相关文章

poj 2778 AC自动机 + 矩阵快速幂

// poj 2778 AC自动机 + 矩阵快速幂 // // 题目链接: // // http://poj.org/problem?id=2778 // // 解题思路: // // 建立AC自动机,确定状态之间的关系,构造出,走一步 // 能到达的状态矩阵,然后进行n次乘法,就可以得到状态间 // 走n步的方法数. // 精髓: // 1):这个ac自动机有一些特别,根节点是为空串,然而 // 每走一步的时候,如果没法走了,这时候,不一定是回到根 // 节点,因为有可能单个的字符时病毒,这样

POJ 2778 AC自动机+矩阵幂 不错的题

http://poj.org/problem?id=2778 有空再重新做下,对状态图的理解很重要 题解: http://blog.csdn.net/morgan_xww/article/details/7834801 另外做了矩阵幂的模板: //ac.sz是矩阵的大小 void mulmtr(long long x[MAXNODE][MAXNODE],long long y[MAXNODE][MAXNODE])//y=x*y { ll tmp[MAXNODE][MAXNODE]; for(in

poj 2778 AC自动机构建有向图 + 邻接矩阵快速幂

Problem: 给你m个病毒串,求指定长度n且不含病毒串作为子串的字符串一共有多少种. Analyse: 用AC自动机构建L个状态节点,每个节点的end标记记录是否在这里形成病毒串. 这里有个核心就是,如果当前后缀的子后缀(也就是它的fail指针指向的地方)是病毒串的话, 那么它就是病毒串. 然后根据这个AC自动机的L个节点来建立有向图的邻接矩阵B,B[i][j]代表从i到j状态的路径数量. B[0][j]代表的是从初始状态,还没有任何字符的时候转移到j状态,因为根节点0就是没有任何限制. 然

DNA Sequence POJ - 2778 AC 自动机 矩阵乘法

定义重载运算的时候一定要将矩阵初始化,因为这个调了一上午...... Code: #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<string> #define maxn 100000 typedef long long ll; using namespace std; void setIO(string a){ freopen((a+

poj 2778 AC自己主动机 + 矩阵高速幂

// poj 2778 AC自己主动机 + 矩阵高速幂 // // 题目链接: // // http://poj.org/problem?id=2778 // // 解题思路: // // 建立AC自己主动机,确定状态之间的关系,构造出,走一步 // 能到达的状态矩阵,然后进行n次乘法,就能够得到状态间 // 走n步的方法数. // 精髓: // 1):这个ac自己主动机有一些特别,根节点是为空串,然而 // 每走一步的时候,假设没法走了,这时候,不一定是回到根 // 节点,由于有可能单个的字符

POJ 4052 AC自动机

[题意]: 给你n个字符串和一个文本,问有多少个字符串满足如下条件:该字符串包含在文本,该字符串不为其它字符串的子串. [知识点]: Ac自动机,处理字符串 [题解]: 集训比赛的时候当时被题目的数据量吓到了,不敢用ac自动机.但在网上看到题解时,然后瞬间就感觉自己想多了... 很水的一道ac自动机处理字符串的题目,先将查询的字符做成字典树,然后在文本中查找字符串是否存在. 在处理去子串上,我的做法是查找文本时去除后缀相同的包含子串.然后单独在搜索剩余可用字符串前缀相同子串. [代码]: 1 #

hdu 4878 ZCC loves words(AC自动机+dp+矩阵快速幂+中国剩余定理)

hdu 4878 ZCC loves words(AC自动机+dp+矩阵快速幂+中国剩余定理) 题意:给出若干个模式串,总长度不超过40,对于某一个字符串,它有一个价值,对于这个价值的计算方法是这样的,设初始价值为V=1,假如这个串能匹配第k个模式串,则V=V*prime[k]*(i+len[k]),其中prime[k]表示第k个素数,i表示匹配的结束位置,len[k]表示第k个模式串的长度(注意,一个字符串可以多次匹配同意个模式串).问字符集为'A'-'Z'的字符,组成的所有的长为L的字符串,

DNA Sequence(POJ2778 AC自动机dp+矩阵加速)

传送门 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 DNA Sequence,For example, if a animal's DNA sequenc

POJ 3691 (AC自动机+状态压缩DP)

题目链接:  http://poj.org/problem?id=3691 题目大意:给定N的致病DNA片段以及一个最终DNA片段.问最终DNA片段最少修改多少个字符,使得不包含任一致病DNA. 解题思路: 首先说一下AC自动机在本题中的作用. ①字典树部分:负责判断当前0~i个字符组成的串是否包含致病DNA,这部分靠字典树上的cnt标记完成. ②匹配部分:主要依赖于匹配和失配转移关系的计算,这部分非常重要,用来构建不同字符间状态压缩的转移关系(代替反人类的位运算). 这也是必须使用AC自动机而