CodeForces 86C Genetic engineering
原题地址:http://codeforces.com/problemset/problem/86/C
题意:
基因是一段有遗传效应DNA片段,我们认为这个片段仅由”A”,”T”,”C”,”G”组成,为了方便,我们只需考虑DNA的一条链。
一条DNA单链长度为n,给出m种基因片段(字符串)的集合,希望使得这条链上的每一个位置都受到可以被集合中的基因片段覆盖。注意有基因片段的序列可以相互重叠,一个位置被覆盖当且仅当它被至少一个集合中的序列包含。
问多少种满足条件的链,对1e9+9取模。
数据范围
1<=n<=1000,1<=m<=10 ,集合中的每个序列长度不超过10。
题解:
(今天的T1)
(我的第一道AC自动机上DP)
dp[n][i][k]表示当前作为DNA链上的第n个点,在AC自动机上的i节点,倒数有长度为k的序列还没有被覆盖。
预处理 val[i]= 点 i 表示的字符串可以覆盖的长度,例如 AGCT,在T对应的点的val值就是4。
那么转移就是:
v点是u点的子节点,此时转移dp[i][u][k],表示当前作为DNA链上的第i个点,在AC自动机上的u节点,倒数有长度为k的序列还没有被覆盖。
若此时 val[v]>=k+1 :
dp[i+1][v][0]+=dp[i][u][k]
(表示到当前点可以覆盖了。)
否则:
dp[i+1][v][j+1]+=dp[i][u][k]
(没覆盖的点又多一个)
能够转移到dp[i+1][v][0],只能转移到dp[i+1][v][0]。否则若遇到后面有个很长的串,两种情况就会都被计算。
我在考试时纠结的点在于,会不会有算重的情况:
eg:
AGCT
AGC
T
实际上,在AC自动机上,AGC的末尾并不会转到T,因为他本身有ch[T],
因此并不会直接从fail树上走到T。
如果每个单词节点都向上面的点连边,显然就会出现上述乱跳的情况。