题目大意:给出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个字符能够得到的所有合法状态的数量。

矩阵的思想非常巧妙。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. using namespace std;
  5. #define MAXN 102
  6. #define MAXL 12
  7. #define MAXC 4
  8. #define MOD 100000
  9. struct node
  10. {
  11. int fail,nxt[6],flag;
  12. }trie[MAXN];
  13. int head,tail,myq[MAXN],root=1,tot=1;
  14. char word[MAXL];
  15. int degree;
  16. int a[MAXN][MAXN],b[MAXN][MAXN],c[MAXN][MAXN],(*ans)[MAXN];
  17. void multi(int (*a)[MAXN],int (*b)[MAXN],int (*c)[MAXN])
  18. {
  19. for(int i=1;i<=degree;i++)
  20. {
  21. for(int j=1;j<=degree;j++)
  22. c[i][j]=0;
  23. }
  24. for(int i=1;i<=degree;i++)
  25. {
  26. for(int j=1;j<=degree;j++)
  27. {
  28. for(int k=1;k<=degree;k++)
  29. {
  30. c[i][j]+=(long long)a[i][k]*b[k][j]%MOD;
  31. c[i][j]%=MOD;
  32. }
  33. }
  34. }
  35. }
  36. void power(int (*t1)[MAXN],int h)
  37. {
  38. for(int i=1;i<=degree;i++)
  39. for(int j=1;j<=degree;j++)
  40. b[i][j]=0;
  41. for(int i=1;i<=degree;i++)
  42. b[i][i]=1;
  43. int (*t2)[MAXN],(*t3)[MAXN];
  44. t2=b,t3=c;
  45. while(h)
  46. {
  47. if(h&1)
  48. {multi(t1,t2,t3);
  49. swap(t2,t3);
  50. }
  51. h>>=1;
  52. multi(t1,t1,t3);
  53. swap(t1,t3);
  54. }
  55. if(t2!=a)
  56. {
  57. memcpy(a,t2,sizeof a);
  58. }
  59. }
  60. int inline getid(char C)
  61. {
  62. if(C=='A')return 0;
  63. else if(C=='T')return 1;
  64. else if(C=='C')return 2;
  65. else return 3;
  66. }
  67. void insert(int r,char *s)
  68. {
  69. int len=strlen(s);
  70. for(int i=0;i<len;i++)
  71. {
  72. int val=getid(s[i]);
  73. if(trie[r].nxt[val]==0)
  74. trie[r].nxt[val]=++tot;
  75. r=trie[r].nxt[val];
  76. }
  77. trie[r].flag=1;//1表示结束节点
  78. }
  79. void build(int r)
  80. {
  81. trie[r].fail=r;
  82. myq[tail++]=r;
  83. int ch;
  84. while(head<tail)
  85. {
  86. r=myq[head++];
  87. for(int i=0;i<MAXC;i++)
  88. {
  89. ch=trie[r].nxt[i];
  90. if(ch)myq[tail++]=ch;
  91. if(r==root)
  92. {
  93. if(ch)
  94. trie[ch].fail=root;
  95. else trie[r].nxt[i]=root;
  96. }
  97. else
  98. {
  99. if(ch)
  100. {trie[ch].fail=trie[trie[r].fail].nxt[i];
  101. trie[ch].flag|=trie[trie[ch].fail].flag;
  102. }
  103. else
  104. trie[r].nxt[i]=trie[trie[r].fail].nxt[i];
  105. }
  106. ch=trie[r].nxt[i];
  107. if(trie[ch].flag!=1)
  108. a[r][ch]++;
  109. }
  110. }
  111. }
  112. int main()
  113. {
  114. int n,m;
  115. scanf("%d%d",&m,&n);
  116. for(int i=0;i<m;i++)
  117. {
  118. scanf("%s",word);
  119. insert(root,word);
  120. }
  121. build(root);
  122. degree=tot;
  123. power(a,n);
  124. int ans=0;
  125. for(int i=1;i<=degree;i++)
  126. {ans+=a[1][i];
  127. ans%=MOD;
  128. }
  129. printf("%d\n",ans);
  130. }

  

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. Excel常用操作

    [对Excel工作表,按某一列数据进行排序] 选中这些数据,在菜单栏上点"数据 - 排序",在弹出的窗口中的主要关键字里选择这一列,按升序或降序,那么其它的数据也会跟着它一一对应变 ...

  2. 当想mysql某插入有某字段设置了unique且和之前相同时,会报错,并停止运行

  3. 路线更改事件 $routeChangeStart 与 $locationChangeStart

    $routeChangeStart属于$route模块,使用将要改变的路由和当前路由对比,在没有跳转之前 参数包括 function(event, next, current)  next $loca ...

  4. CSS元素定位6-10课

    <精通CSS.DIV网页样式与布局>视频6-10课总结图: 元素定位 (1)float:left/right; 左浮动:脱离普通文档流向左浮动(即向左对齐):float属性必须应用在块级元 ...

  5. [Error] ld returned 1 exit status

    试试重启你的编译器,不稳定的编译器可能会有这种情况.当然不排除其他原因,若是重启了还不好使,就要看代码哪写错喽!!

  6. 微信公众号红包接口开发PHP开发 CA证书出错,请登陆微信支付商户平台下载证书

    微信红包接口调试过程中一直提示“CA证书出错,请登陆微信支付商户平台下载证书”,经反复调试,大致解决方法如下: 1.首先确保CA证书的路径是否正确,一定得是绝对路径,因为是PHP开发的,这里需要三个p ...

  7. 10——operator=返回reference to *this

    注意operator=返回一个引用,便于连锁赋值

  8. Activity、Task、应用和进程

    http://www.cnblogs.com/franksunny/archive/2012/04/17/2453403.html Activity.Task.应用和进程 为了阅读方便,将文档转成pd ...

  9. Centos 7防火墙firewalld开放80端口(转)

    开启80端口 firewall-cmd --zone=public --add-port=80/tcp --permanent 出现success表明添加成功 命令含义: --zone #作用域 -- ...

  10. Lua小技巧

    来公司以后,业务逻辑都用lua写.写了好长时间了,到最近才觉得有点掌握了Lua的灵活.最近用Lua写了个类似集合一样的东西,如果两次向集合里放入同一个元素,就会报错,方便检查配置.代码如下: -- k ...