题目链接:https://vjudge.net/problem/POJ-2778

题意:输入n和m表示n个病毒,和一个长为m的字符串,里面只可以有'A','C','G','T' 这四个字符,现在问这个长为m的字符串里面不可以出现任何病毒的情况有多少。

参考的两篇博客:

http://www.cnblogs.com/LQLlulu/p/9344774.html

https://blog.csdn.net/morgan_xww/article/details/7834801

上面的博客写得很好,可以主要看上面的博客(两个一起看)。

写点东西,不一定对。

因为最多10个病毒,每个病毒最多10个字符,所以我们trie树上最多有100个点,其他空的点都指向根节点(也就是说我们把所有的空的节点看成0),这样我们可以到达的点就只有100个(再重复一遍:我们把trie树上面的空节点一律指向根节点,看成0),同时因为有些点是单词的结尾或者他的fail[u]是单词结尾(fail[u]是单词结尾说明当前位置的后缀和fail[u]上的单词相同,这个后缀也不能到达)。

我们一开始先构建一个cnt*cnt的邻接矩阵mat(cnt是trie树上面的节点个数),刚刚构建的mat[i][j]代表从编号为i的点走一步到达编号为j的点的合法(就是不经过单词结尾或fail[u]是单词结尾的点),在离散数学里面有一个结论,就是已知cnt个点之间两两互达(走一步)的可能数量(就是这个cnt*cnt的矩阵已经有了),那么如果我们要计算他们两两之间走n步到达的可能数量,只需要求出矩阵的n次方,这个矩阵的n次方就是点与点之间走n步到达的可能数量,这个可以联想矩阵乘法的计算过程。

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<set>
#include<cstdio>
#include<string>
#include<deque>
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 105
],fail[maxn],val[maxn];
LL mat[maxn][maxn],f[maxn][maxn],ss[maxn][maxn];
//mat[i][j]记录从i到j有多少种可能,f[0][i]记录以i结束的合法可能,其它维没用,ss用来计算时暂时存储
int n,m,k,t,cnt;
];
void init(){
    memset(trie,,sizeof(trie));
    memset(fail,,sizeof(fail));
    memset(val,,sizeof(val));
    memset(mat,,sizeof(mat));
    memset(f,,sizeof(f));
    f[][]=;        //一开始把根节点赋值为1,因为我们只需要第一行,所以可以只把f[0][0]赋值为1
    /*for(int i=0;i<maxn;i++)
    f[i][i]=1; */    //也可以这样
    cnt=;
}
int getID(char a){
    if(a=='A')
    ;
    if(a=='T')
    ;
    if(a=='C')
    ;
    if(a=='G')
    ;
}
void insert(char *s){
    ;
    ;s[i];i++){
        int id=getID(s[i]);
        )
        trie[root][id]=++cnt;
        root=trie[root][id];
    }
    val[root]=;//标记单词结尾
}
void build_fail(){
    queue<int>q;
    ;
    ;i<;i++){
        if(trie[root][i])
        q.push(trie[root][i]);
    }
    while(!q.empty()){
        int u=q.front();
        q.pop();
        if(val[fail[u]])//如果这个后缀是一个病毒,那么这个后缀也不可以到达
        val[u]=;
        ;i<;i++){
            if(trie[u][i]){
                fail[trie[u][i]]=trie[fail[u]][i];
                q.push(trie[u][i]);
            }else{
                trie[u][i]=trie[fail[u]][i];
            }
        }
    }
}
void build_mat(){//建图
    ;i<=cnt;i++){
        ;j<;j++){
            &&val[i]==)//当前状态或接下来的的状态是病毒都是不可以到达的
            mat[i][trie[i][j]]++;
        }
    }
}
void muti(LL a[][maxn],LL b[][maxn]){//矩阵快速幂
    memset(ss,,sizeof(ss));
    ;k<=cnt;k++)
    ;i<=cnt;i++){
        ;j<=cnt;j++){
            ss[i][j]+=a[i][k]*b[k][j];
            ss[i][j]%=;
        }
    }
    ;i<=cnt;i++){
        ;j<=cnt;j++){
            a[i][j]=ss[i][j];
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF){
        init();
        ;i<n;i++){
            scanf("%s",s);
            insert(s);
        }
        build_fail();
        build_mat();//获得走1步时的矩阵
        while(m){
            )
            muti(f,mat);
            muti(mat,mat);
            m>>=;
        }
        LL ans=;
        ;i<=cnt;i++)
        ans=(ans+f[][i])%;
        printf("%lld\n",ans);
    }
    ;
}

poj 2778 AC自动机+矩阵快速幂的更多相关文章

  1. 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 ...

  2. POJ - 2778 ~ HDU - 2243 AC自动机+矩阵快速幂

    这两题属于AC自动机的第二种套路通过矩阵快速幂求方案数. 题意:给m个病毒字符串,问长度为n的DNA片段有多少种没有包含病毒串的. 根据AC自动机的tire图,我们可以获得一个可达矩阵. 关于这题的t ...

  3. POJ 2778 DNA Sequence(AC自动机 + 矩阵快速幂)题解

    题意:给出m个模式串,要求你构造长度为n(n <= 2000000000)的主串,主串不包含模式串,问这样的主串有几个 思路:因为要不包含模式串,显然又是ac自动机.因为n很大,所以用dp不太好 ...

  4. POJ 2778 DNA Sequence (ac自动机+矩阵快速幂)

    DNA Sequence Description It's well known that DNA Sequence is a sequence only contains A, C, T and G ...

  5. POJ 2778 DNA Sequence (矩阵快速幂 + AC自动鸡)

    题目:传送门 题意: 给你m个病毒串,只由(A.G.T.C) 组成, 问你生成一个长度为 n 的 只由 A.C.T.G 构成的,不包含病毒串的序列的方案数. 解: 对 m 个病毒串,建 AC 自动机, ...

  6. POJ 2778 (AC自动机+矩阵乘法)

    POJ 2778 DNA Sequence Problem : 给m个只含有(A,G,C,T)的模式串(m <= 10, len <=10), 询问所有长度为n的只含有(A,G,C,T)的 ...

  7. 考研路茫茫——单词情结 HDU - 2243 AC自动机 && 矩阵快速幂

    背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了. 一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如"ab",放在单词前一般 ...

  8. POJ2778 DNA Sequence(AC自动机+矩阵快速幂)

    题目给m个病毒串,问不包含病毒串的长度n的DNA片段有几个. 感觉这题好神,看了好久的题解. 所有病毒串构造一个AC自动机,这个AC自动机可以看作一张有向图,图上的每个顶点就是Trie树上的结点,每个 ...

  9. hdu 2243 考研路茫茫——单词情结 ac自动机+矩阵快速幂

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=2243 题意:给定N(1<= N < 6)个长度不超过5的词根,问长度不超过L(L <23 ...

随机推荐

  1. [IIS]win7下怎么安装IIS

  2. Linux 常用性能分析命令

    性能分析 vmstat 虚拟内存统计 用法 Usage: vmstat [options] [delay [count]] Options: -a, --active           active ...

  3. .net core2 单元测试

    1.下载   https://marketplace.visualstudio.com/items?itemName=RandomEngy.UnitTestBoilerplateGenerator 2 ...

  4. React面试题

    React 简述下React的生命周期,性能优化在哪个生命周期,ajax操作在哪个生命周期 React中key的作用是什么 什么是虚拟DOM diff算法原理 React中refs的作用是什么

  5. Java Base64位加密和解密(包括其他加密参考)

    链接https://blog.csdn.net/longguangfu8/article/details/78948213 常用加密解密算法[RSA.AES.DES.MD5]介绍和使用 https:/ ...

  6. Error occurred during initialization of VM Could not reserve enough space for object heap

    Error occurred during initialization of VM Could not reserve enough space for object heap Java虚拟机(JV ...

  7. Linux基本指令

    常用目录文件作用 - /    根目录 - /bin    命令保存目录(普通用户就可以读取的命令) - /boot    启动目录,启动相关文件 - /dev    设备文件保存目录 - /etc  ...

  8. pl-svo在ROS下运行笔记

    一.程序更改的思路(参考svo_ros的做法): 1.在ROS下将pl-svo链接成库需要更改相应的CMakeLists.txt文件,添加package.xml文件: 2.注册一个ROS节点使用svo ...

  9. .yaml参数文件的编写和使用

    一.在ROS底下使用.yaml文件配置参数 在ROS底下用起来还是非常方便的,首先,写一个读参数的函数getParam(),由于参数类型不止一种,所以要使用模板. 具体语句如下: template&l ...

  10. 使用DatagramSocket和DatagramPacket进行简单的通信

    DatagramSocket此类表示用来发送和接收数据报包的套接字. DatagramPacket此类表示数据报包. package cn.sxt.UdpDemo; import java.io.IO ...