题目大意:
现在给出m个( 0 <= m <= 10)个遗传病的DNA序列,问长度为n( 1 <= n <= 2e9)的DNA序列中有多少种是不包含这些带病的序列的,输出结果对1e6取模后输出
大致思路:
首先用AC自动机建立状态转移图,这样对于编号为 now的点,如果next[now][ ‘A', G', 'C', T']中的下一个点不会出现病串,则从now到next[now]['A', 'G', 'C', 'T'] 的路增加一条,这样可以得到一个矩阵,矩阵的第 i 行 j 列代表从节点 i 到 节点 j 有多少种不同的路,这个矩阵当中可以不包括遗传病结尾的点,需要注意的是如果节点 now 不是插入序列的结尾, 但是fail[now]是的话也不能算是可用的点,bfs建立矩阵然后用快速幂计算即可最后矩阵的第0行的和就是结果
由于中间结果可能超出int范围需要使用long long
代码如下:
Result : Accepted Memory : 1496 KB Time : 110 ms
/*
* Author: Gatevin
* Created Time: 2014/11/19 10:00:53
* File Name: Kagome.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
int m, n;
map<char, int> M;
int bound;
const lint mod = 100000LL;
struct Matrix
{
lint a[110][110];
Matrix()
{
for(int i = 0; i < 110; i++)
for(int j = 0; j < 110; j++)
a[i][j] = i == j ? 1 : 0;
return;
}
lint* operator[](int i)
{
return a[i];
}
};
Matrix operator*(Matrix m1, Matrix m2)
{
Matrix rm;
for(int i = 0; i < bound; i++)
for(int j = 0; j < bound; j++)
{
rm[i][j] = 0;
for(int k = 0; k < bound; k++)
{
rm[i][j] += m1[i][k]*m2[k][j];
}
rm[i][j] %= mod;
}
return rm;
}
Matrix quick(Matrix base, int pow)//矩阵快速幂
{
Matrix I;
while(pow)
{
if(pow & 1)
I = I*base;
base = base*base;
pow >>= 1;
}
return I;
}
struct Trie
{
int next[110*5][4], fail[110*5];
bool end[110*5], vis[110*5];
int L, root;
int newnode()
{
for(int i = 0; i < 4; i++)
next[L][i] = -1;
end[L++] = 0;
return L - 1;
}
void init()
{
L = 0;
root = newnode();
return;
}
void insert(char* s)
{
int now = root;
for(; *s; s++)
{
if(next[now][M[*s]] == -1)
next[now][M[*s]] = newnode();
now = next[now][M[*s]];
}
end[now] = 1;
return;
}
void build()//建立状态转移图
{
fail[root] = root;
queue <int> Q;
Q.push(root);
while(!Q.empty())
{
int now = Q.front();
Q.pop();
if(end[fail[now]]) end[now] = true;//注意标记end节点
for(int i = 0; i < 4; i++)
if(next[now][i] == -1)
next[now][i] = now == root ? root : next[fail[now]][i];
else
{
fail[next[now][i]] = now == root ? root : next[fail[now]][i];
Q.push(next[now][i]);
}
}
return;
}
Matrix matrix()
{
lint ret[110][110];
memset(ret, 0, sizeof(ret));
memset(vis, 0, sizeof(vis));
queue <int> Q;
Q.push(root);
vis[root] = 1;
while(!Q.empty())//bfs建立矩阵
{
int now = Q.front();
Q.pop();
for(int i = 0; i < 4; i++)
if(!end[next[now][i]])
{
ret[now][next[now][i]]++;
if(!vis[next[now][i]])
{
Q.push(next[now][i]);
vis[next[now][i]] = 1;
}
}
}
Matrix R;
vector <int> v;
for(int i = 0; i < L; i++)//去掉矩阵中不需要的行和列
if(vis[i]) v.push_back(i);
for(unsigned int i = 0; i < v.size(); i++)
for(unsigned int j = 0; j < v.size(); j++)
R[i][j] = ret[v[i]][v[j]];
bound = v.size();
return R;
}
};
Trie AC;
void init()
{
M['A'] = 0; M['C'] = 1; M['G'] = 2; M['T'] = 3;
return;
}
int main()
{
char ts[12];
init();
while(~scanf("%d %d", &m, &n))
{
AC.init();
while(m--)
{
scanf("%s", ts);
AC.insert(ts);
}
AC.build();
Matrix A = AC.matrix();
A = quick(A, n);
lint ans = 0;
for(int i = 0; i < bound; i++)
ans += A[0][i];
ans %= mod;
printf("%I64d\n", ans);
}
return 0;
}