题目大意:
现在给出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; }