POJ2778 DNA sequence
题目大意:给出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的更多相关文章
- poj2778 DNA Sequence【AC自动机】【矩阵快速幂】
DNA Sequence Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 19991 Accepted: 7603 Des ...
- 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 ...
- POJ2778 DNA Sequence(AC自动机+矩阵快速幂)
题目给m个病毒串,问不包含病毒串的长度n的DNA片段有几个. 感觉这题好神,看了好久的题解. 所有病毒串构造一个AC自动机,这个AC自动机可以看作一张有向图,图上的每个顶点就是Trie树上的结点,每个 ...
- 【AC自动机】【矩阵乘法】poj2778 DNA Sequence
http://blog.csdn.net/morgan_xww/article/details/7834801 讲得很好~可以理解自动机的本质,就是一个用来状态转移的东西~对于确定的输入而言,可以从初 ...
- [poj2778]DNA Sequence(AC自动机+矩阵快速幂)
题意:有m种DNA序列是有疾病的,问有多少种长度为n的DNA序列不包含任何一种有疾病的DNA序列.(仅含A,T,C,G四个字符) 解题关键:AC自动机,实际上就是一个状态转移图,注意能少取模就少取模, ...
- [日常摸鱼]poj2778 DNA Sequence
这题太神啦 题意:求长度为$n$的不包含给定DNA序列的DNA序列个数,给定的不超过10个 构建出Trie图,用$danger[i]$来表示不能走到$i$,对于DNA序列结尾的结点$danger$设为 ...
- POJ2778 DNA Sequence(AC自动机 矩阵)
先使用AC自动机求得状态转移关系,再建立矩阵,mat[i][j]表示一步可从i到j且i,j节点均非终止字符的方案数,则此矩阵的n次方表示n步从i,到j的方法数. #include<cstdio& ...
- [POJ2778]DNA Sequence(AC自动机 + DP + 矩阵优化)
传送门 AC自动机加DP就不说了 注意到 m <= 10,所以模式串很少. 而 n 很大就需要 log 的算法,很容易想到矩阵. 但是该怎么构建? 还是矩阵 A(i,j) = ∑A(i,k) * ...
- [poj2778 DNA Sequence]AC自动机,矩阵快速幂
题意:给一些字符串的集合S和整数n,求满足 长度为n 只含charset = {'A'.'T‘.'G'.'C'}包含的字符 不包含S中任一字符串 的字符串的种类数. 思路:首先对S建立ac自动机,考虑 ...
随机推荐
- Excel常用操作
[对Excel工作表,按某一列数据进行排序] 选中这些数据,在菜单栏上点"数据 - 排序",在弹出的窗口中的主要关键字里选择这一列,按升序或降序,那么其它的数据也会跟着它一一对应变 ...
- 当想mysql某插入有某字段设置了unique且和之前相同时,会报错,并停止运行
- 路线更改事件 $routeChangeStart 与 $locationChangeStart
$routeChangeStart属于$route模块,使用将要改变的路由和当前路由对比,在没有跳转之前 参数包括 function(event, next, current) next $loca ...
- CSS元素定位6-10课
<精通CSS.DIV网页样式与布局>视频6-10课总结图: 元素定位 (1)float:left/right; 左浮动:脱离普通文档流向左浮动(即向左对齐):float属性必须应用在块级元 ...
- [Error] ld returned 1 exit status
试试重启你的编译器,不稳定的编译器可能会有这种情况.当然不排除其他原因,若是重启了还不好使,就要看代码哪写错喽!!
- 微信公众号红包接口开发PHP开发 CA证书出错,请登陆微信支付商户平台下载证书
微信红包接口调试过程中一直提示“CA证书出错,请登陆微信支付商户平台下载证书”,经反复调试,大致解决方法如下: 1.首先确保CA证书的路径是否正确,一定得是绝对路径,因为是PHP开发的,这里需要三个p ...
- 10——operator=返回reference to *this
注意operator=返回一个引用,便于连锁赋值
- Activity、Task、应用和进程
http://www.cnblogs.com/franksunny/archive/2012/04/17/2453403.html Activity.Task.应用和进程 为了阅读方便,将文档转成pd ...
- Centos 7防火墙firewalld开放80端口(转)
开启80端口 firewall-cmd --zone=public --add-port=80/tcp --permanent 出现success表明添加成功 命令含义: --zone #作用域 -- ...
- Lua小技巧
来公司以后,业务逻辑都用lua写.写了好长时间了,到最近才觉得有点掌握了Lua的灵活.最近用Lua写了个类似集合一样的东西,如果两次向集合里放入同一个元素,就会报错,方便检查配置.代码如下: -- k ...