题目大意:给出m个疾病基因片段(m<=10),每个片段不超过10个字符。求长度为n的不包含任何一个疾病基因片段的DNA序列共有多少种?(n<=2000000000)

分析:本题需要对m个疾病基因片段构建一个AC自动机,自动机中的每个节点表示一个状态。其中AC自动机中的叶子节点表示的是病毒,所以是非法状态。同时,如果某个节点到根的字符串的后缀是一个病毒,那么该节点也是非法状态。剔除掉所有的非法状态,那么剩下的节点都表示合法状态了。然后用节点的nxt指针表示状态之间转化关系。若nxt[i]==0,则nxt[i]指针指向当前节点fail指针的nxt[i],如果仍然为0,则nxt[i]指向根节点。这样处理以后,每个指针都不会指向0。这样,该自动机可以看做是一个合法状态的转换图,节点表示各种合法状态,边表示添加一个字符将转换为另一个状态。于是我们可以得到一个矩阵。该矩阵实际上表示该状态图的邻接矩阵。对该矩阵自乘n次。最后结果矩阵的第1行各元素之和表示从空状态添加n个字符能够得到的所有合法状态的数量。

矩阵的思想非常巧妙。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 102
#define MAXL 12
#define MAXC 4
#define MOD 100000
struct node
{
int fail,nxt[6],flag;
}trie[MAXN];
int head,tail,myq[MAXN],root=1,tot=1;
char word[MAXL];
int degree;
int a[MAXN][MAXN],b[MAXN][MAXN],c[MAXN][MAXN],(*ans)[MAXN];
void multi(int (*a)[MAXN],int (*b)[MAXN],int (*c)[MAXN])
{
for(int i=1;i<=degree;i++)
{
for(int j=1;j<=degree;j++)
c[i][j]=0;
}
for(int i=1;i<=degree;i++)
{
for(int j=1;j<=degree;j++)
{
for(int k=1;k<=degree;k++)
{
c[i][j]+=(long long)a[i][k]*b[k][j]%MOD;
c[i][j]%=MOD;
}
}
}
}
void power(int (*t1)[MAXN],int h)
{
for(int i=1;i<=degree;i++)
for(int j=1;j<=degree;j++)
b[i][j]=0;
for(int i=1;i<=degree;i++)
b[i][i]=1;
int (*t2)[MAXN],(*t3)[MAXN];
t2=b,t3=c;
while(h)
{
if(h&1)
{multi(t1,t2,t3);
swap(t2,t3);
}
h>>=1;
multi(t1,t1,t3);
swap(t1,t3);
}
if(t2!=a)
{
memcpy(a,t2,sizeof a);
}
}
int inline getid(char C)
{
if(C=='A')return 0;
else if(C=='T')return 1;
else if(C=='C')return 2;
else return 3;
}
void insert(int r,char *s)
{
int len=strlen(s);
for(int i=0;i<len;i++)
{
int val=getid(s[i]);
if(trie[r].nxt[val]==0)
trie[r].nxt[val]=++tot;
r=trie[r].nxt[val];
}
trie[r].flag=1;//1表示结束节点
}
void build(int r)
{
trie[r].fail=r;
myq[tail++]=r;
int ch;
while(head<tail)
{
r=myq[head++];
for(int i=0;i<MAXC;i++)
{
ch=trie[r].nxt[i];
if(ch)myq[tail++]=ch;
if(r==root)
{
if(ch)
trie[ch].fail=root;
else trie[r].nxt[i]=root;
}
else
{
if(ch)
{trie[ch].fail=trie[trie[r].fail].nxt[i];
trie[ch].flag|=trie[trie[ch].fail].flag;
}
else
trie[r].nxt[i]=trie[trie[r].fail].nxt[i];
}
ch=trie[r].nxt[i];
if(trie[ch].flag!=1)
a[r][ch]++;
}
}
}
int main()
{
int n,m;
scanf("%d%d",&m,&n);
for(int i=0;i<m;i++)
{
scanf("%s",word);
insert(root,word);
}
build(root);
degree=tot;
power(a,n);
int ans=0;
for(int i=1;i<=degree;i++)
{ans+=a[1][i];
ans%=MOD;
}
printf("%d\n",ans);
}

  

POJ2778 DNA sequence的更多相关文章

  1. poj2778 DNA Sequence【AC自动机】【矩阵快速幂】

    DNA Sequence Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 19991   Accepted: 7603 Des ...

  2. 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 ve ...

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

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

  4. 【AC自动机】【矩阵乘法】poj2778 DNA Sequence

    http://blog.csdn.net/morgan_xww/article/details/7834801 讲得很好~可以理解自动机的本质,就是一个用来状态转移的东西~对于确定的输入而言,可以从初 ...

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

    题意:有m种DNA序列是有疾病的,问有多少种长度为n的DNA序列不包含任何一种有疾病的DNA序列.(仅含A,T,C,G四个字符) 解题关键:AC自动机,实际上就是一个状态转移图,注意能少取模就少取模, ...

  6. [日常摸鱼]poj2778 DNA Sequence

    这题太神啦 题意:求长度为$n$的不包含给定DNA序列的DNA序列个数,给定的不超过10个 构建出Trie图,用$danger[i]$来表示不能走到$i$,对于DNA序列结尾的结点$danger$设为 ...

  7. POJ2778 DNA Sequence(AC自动机 矩阵)

    先使用AC自动机求得状态转移关系,再建立矩阵,mat[i][j]表示一步可从i到j且i,j节点均非终止字符的方案数,则此矩阵的n次方表示n步从i,到j的方法数. #include<cstdio& ...

  8. [POJ2778]DNA Sequence(AC自动机 + DP + 矩阵优化)

    传送门 AC自动机加DP就不说了 注意到 m <= 10,所以模式串很少. 而 n 很大就需要 log 的算法,很容易想到矩阵. 但是该怎么构建? 还是矩阵 A(i,j) = ∑A(i,k) * ...

  9. [poj2778 DNA Sequence]AC自动机,矩阵快速幂

    题意:给一些字符串的集合S和整数n,求满足 长度为n 只含charset = {'A'.'T‘.'G'.'C'}包含的字符 不包含S中任一字符串 的字符串的种类数. 思路:首先对S建立ac自动机,考虑 ...

随机推荐

  1. 关于JAVA的数据转换总结

    数据转换在编程里面是十分常用的,将平常可能用到的数据转换类型总结起来会在以后码代码的过程中有很大帮助. 在数据转换之前,需要明白的是基础数据类型的自动转换和强制转换.接下来就先从数据类型的容量讲起. ...

  2. Android 开发常用命令

    1.生成keystore文件 keytool -exportcert -keystore keystore_path -list -v 2.查看APK签名 keytool -list -printce ...

  3. cnblogs开篇留念

    之前看过很多大牛程序员们介绍的一些经验之类的文章,几乎每个人都提到了一点就是平时要写博客,记录一些自己平时学习和工作过程中学习到的一些技术点和心得.之前也用过一些其他的网站博客,上周有同事推荐了一篇文 ...

  4. 解决织梦DEDEcms指定arclist的特定ID排序的方法

    转载网址:http://blog.hrseo.net/xuexi/184.html 替换/include/taglib/arclist.lib.php这个文件,下载链接: http://pan.bai ...

  5. Android activity和service的生命周期对比

    1Activity生命周期 七个方法 1. void onCreate(Bundle savedInstanceState) 当Activity被第首次加载时执行.我们新启动一个程序的时候其主窗体的o ...

  6. Entity Framework关联查询以及数据加载(延迟加载,预加载)

    数据加载分为延迟加载和预加载 EF的关联实体加载有三种方式:Lazy Loading,Eager Loading,Explicit Loading,其中Lazy Loading和Explicit Lo ...

  7. SQL Server 2008 R2 未能加载文件或程序集Microsoft.SqlServer.Sqm...

    错误提示:未能加载文件或程序集“Microsoft.SqlServer.Sqm, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8 ...

  8. swift开源项目精选

    Swift 开源项目精选-v1.0 2016-03-07 22:11 542人阅读 评论(0) 收藏 举报  分类: iOS(55)   Swift(4)    目录(?)[+]   转自 http: ...

  9. 【引】objective-c,5:Associated Objects 的原理

    参考博客: http://blog.leichunfeng.com/blog/2015/06/26/objective-c-associated-objects-implementation-prin ...

  10. 05_动手动脑之String.equals()方法的实现代码

    Question: 请查看String.equals()方法的实现代码,注意学习其实现方法. Answer: java中的String.equals()方法的实现代码: equals()法是根类Obj ...