Description
It’s well known that DNA Sequence is a sequence only contains A, C, T
and G, and it’s very useful to analyze a segment of DNA Sequence,For
example, if a animal’s DNA sequence contains segment ATC then it may
mean that the animal may have a genetic disease. Until now scientists
have found several those segments, the problem is how many kinds of
DNA sequences of a species don’t contain those segments.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
First line contains two integer m (0 <= m <= 10), n (1 <= n
<=2000000000). Here, m is the number of genetic disease segment, and n
is the length of sequences.Next m lines each line contain a DNA genetic disease segment, and
length of these segments is not larger than 10.
Output
An integer, the number of DNA sequences, mod 100000.
Sample Input
4 3
AT
AC
AG
AA
Sample Output
36
思路
先吐槽一下,AC自动机做了3道水题,以为会的差不多了,结果这题的难度骤增,看了三天才有点眉目~果然还是太菜o(╥﹏╥)o
现在说一说题意,这个题题意是首先给你一个n和m,然后n行病毒序列,给出一个长度m,要求这个长m的序列里面不包含前面给出的病毒序列,问符合条件的长度为m的串一共有多少种。
然后思路是,先构造AC自动机,然后利用end
来标记这个串是不是病毒串。
以一个例子来说明一下:{“ACG”,”C”}
(参考:Poj 2778 [AC自动机,矩阵乘法])
首先构造字典树:
然后我们给他们编上号码,每个编号代表每一种状态,分别是:0 1 2 3 4
那么假设我们当前在根节点,现在只走一步,我们能到达哪些状态?一共有ATCG这四种可能:
- 走A:走A的话,很明显会到达状态1(安全)
- 走T:走T的话,根据我们构造的fail指针,根节点里面没有T这个儿子,所以又会回到A节点,所以走T会达到状态0(安全)
- 走G:走G的话,和上面的T一样,还会回到状态0(安全)
- 走C:走C的话,因为根节点有C儿子,所以走C会变成状态4(病毒,危险)
所以当n的值为1的时候,有3个安全的节点,所以我们的走法有3种
我们根据上面的走法,可以构建一个矩阵:
- mat[i][j]:代表从状态i到状态j,只走一步,有几种走法
也就是上面的那张图,我们可以构建一个矩阵:
2 1 0 0 1
2 1 1 0 0
1 1 0 1 1
2 1 0 0 1
2 1 0 0 1
这是一个5*5的矩阵,行号和列号都是从0~4,代表从i状态到j状态只走一步有几种走法
现在我们要走m步,应该怎么办呢,我们矩阵构建的是走一步有几种走法,那么走m步只需要把这个矩阵乘以m次就可以了,因为m可能太大,因此这里要用到矩阵快速幂
题目上求的是,不能包含病毒序列的种数,那么我们上面构建的矩阵是包含病毒序列的,很明显不符合题意,那么我们只需要把有病毒的节点的行和列中的所有值变成0,这样就可以符合题意,例如上面构建的矩阵去除病毒序列后矩阵就变成了:
2 1 0 0 0
2 1 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
我们只需要算出最后的序列第一行的和对100000取模就可以了
代码
#include <cstdio>
#include <cstring>
#include <string>
#include <set>
#include <sstream>
#include <cmath>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int N=110;
const int mod=100000;
struct Matrix
{
int mat[N][N], n;
Matrix() {}
Matrix(int _n)
{
n = _n;
mem(mat,0);
}
Matrix operator*(const Matrix &b) const
{
Matrix ret = Matrix(n);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
for (int k = 0; k < n; k++)
{
int tmp = (long long)mat[i][k] * b.mat[k][j] % mod;
ret.mat[i][j] = (ret.mat[i][j] + tmp) % mod;
}
return ret;
}
};
Matrix mat_pow(Matrix a, int n)
{
Matrix ret = Matrix(a.n);
for (int i = 0; i < ret.n; i++)
ret.mat[i][i] = 1;
Matrix tmp = a;
while (n)
{
if (n & 1)
ret = ret * tmp;
tmp = tmp * tmp;
n >>= 1;
}
return ret;
}
struct dicTree
{
int next[N][4],fail[N];
bool end[N];
int root,sz;
int newnode()
{
for(int i=0; i<4; i++)
next[sz][i]=-1;
end[sz++]=0;
return sz-1;
}
void init()
{
sz=0;
root=newnode();
}
int getch(char ch)
{
if(ch=='A')return 0;
if(ch=='C')return 1;
if(ch=='G')return 2;
if(ch=='T')return 3;
}
void insert(char *s)
{
int len=strlen(s);
int now=root;
for(int i=0; i<len; i++)
{
int to=getch(s[i]);
if(next[now][to]==-1)
next[now][to]=newnode();
now=next[now][to];
}
end[now]=true;
}
void build()
{
queue<int>q;
fail[root]=root;
for(int i=0; i<4; i++)
{
if(next[root][i]==-1)
next[root][i]=root;
else
{
fail[next[root][i]]=root;
q.push(next[root][i]);
}
}
while(!q.empty())
{
int now=q.front();
q.pop();
if(end[fail[now]]==true)
end[now]=true;
for(int i=0; i<4; i++)
{
if(next[now][i]==-1)
next[now][i]=next[fail[now]][i];
else
{
fail[next[now][i]]=next[fail[now]][i];
q.push(next[now][i]);
}
}
}
}
Matrix get_mat()
{
Matrix res=Matrix(sz);
for(int i=0; i<sz; i++)
for(int j=0; j<4; j++)
if(end[next[i][j]]==false&&end[i]==false)
res.mat[i][next[i][j]]++;
return res;
}
};
dicTree ac;
char s[N];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
ac.init();
for(int i=0; i<n; i++)
{
scanf("%s",s);
ac.insert(s);
}
ac.build();
Matrix a=ac.get_mat();
a=mat_pow(a,m);
int ans=0;
for(int i=0; i<ac.sz; i++)
ans=(ans+a.mat[0][i])%mod;
printf("%d\n",ans);
}
return 0;
}