Description
Suppose that DNA sequences of a species is a sequence that consist of A, C, T and G,and the length of sequences is a given integer n.
Input
Next m lines each line contain a DNA genetic disease segment, and length of these segments is not larger than 10.
Output
Sample Input
4 3 AT AC AG AA
Sample Output
36
PKU2778 DNA Squence ccsu_010 原创
在A这道题之前,A了pku3691,跟这道题这不错,应该还比较难吧。这里是给定M个病毒DNA,求组成长度为N的DNA序列的个数,3691是在给定M个病毒之后,给定一个DNA序列,然后求最小修改几个字符可以使它不含病毒序列(AC自动机+dp)。
两道题都要注意,当某病毒片段为其子序列时,它也就会是危险序列。
这道题参考了AC大牛的博文。他构造的DFA给了我启发(之前什么都不懂,DFA什么意思都是AC大牛告诉的,在此3Q一下)。
虽然会建AC自动机,可是不知道怎么运用。
先看一下样例数据
4 3
AT
AC
AG
AA
我这里的自动机是基于静态trie的。按照常规方法建立就可以了,但还是要注意它的子串。假如我们建立了自动机,接下来就是如何构造矩阵了。先看上面的数据。虚线指向它的fail。红色为末结点,不能出现在生成的序列中。
图中有6个结点,代表6种状态,S0是起点,可以代表其它安全状态。它的son[T,C,G]为-1(空指针),如果在它后面加T,C,G肯定会是安全的。所以dp[n][0]=3*dp[n-1][0]+x; x表示可能其它状态会有转移到S0。dp[i][j]表示长为i后缀状态为j的DNA数。
在看S1,它的son[T,C,G,A]都不为 -1,当添加一个字符时,必然会到它的son[]的状态,不可能回到S0,所以上面的x=0(都不符合条件)。
S1 的son都有,但是却都是末结点——危险,不用回来了,则S1只能由S0+A得来。所以dp[n][1]= dp[n-1][0]; 其它都为0.
我们用矩阵g[i][j]表示:从第i个结点(状态)到第j个结点有g[i][j]种情况。
得到矩阵
,然后在求该矩阵的N次方,答案就是ans+=tot[0][i]。矩阵中3=『S0加一个字母到S0有三条路径,dp公式中不是×3了嘛』,1=『S0添加一个字母到S1只有一条路径,即+A』,前面分析了S1到S0是没有转移路径的,S1添加任何字母都会到他的son去。
这组数据太简单,再看一组,看fail是怎么运用的。
2 3
AG
CG
S0,S1,S2,S3,S4,可以看作插入后,存储的顺序。上图表示后缀加该字符转移到另一状态。我们按顺序从S0->S4考虑,当然危险的(S2,S4)就不用考虑了。
1.先看S0,它的son[T]和son[G]为-1,所以可以直接转移。G[i][0]+2 (i==0,2->T/G)。
2.S1,son[G]!=-1但是son[G].end>0,即危险,所以不要管。Son[A]= -1, 如果在S1后面加个A,是否会危险呢??因为它的son[A]=-1,所以我们只有看它的fail了,(根据AC自动机性质知,从根到它的fail的序列是它的最长后缀,如果Si.fail.son[A].end>0,那在S1后加A也会危险的),在这里,S1的fail为S0,而S0.son[A]就是S1,不为-1,而且S1.end==0,所以S1后面可以+A,S1.fail+A后回到S1,g[1][1]++,即S1可以回到本状态。同样的,对于每一结点Si(状态),它的AGCT四个后继都要分析,如果son[j]==-1(即空指针)我们就看它的fail.son[j]是否不为-1,直到S0,哪个son[j]不为-1,那么Si+[j代表的字符]就可以转移到 它的son[j]所在的结点。例如S1转到S1, 因为它的fail(也就是S0)的son[A]就是S1. 如果它的son[j]不为-1,我们直接往下看,如果它的son[j].end==0(不危险)那g[i][son[j]所在的位置]++;
第二个例子得到矩阵
。
即 dp[n][0] =2*dp[n-1][]+dp[n-1][1]+dp[n-1][3];
dp[n][1] =dp[n-1][1] + dp[n-1][1] + dp[n-1][3];
dp[n][3] =dp[n-1][0] + dp[n-1][1] + dp[n-1][3];其它的没必要算,都为0.
下面就可以去pku1625~