POJ 2778 DNA Sequence (ac自动机+矩阵快速幂)
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.
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.
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
题目大意:给定n个病毒序列,求长度为m的序列里面不含有这n种病毒序列的有多少种。
思路:参考了https://blog.csdn.net/qq_36346262/article/details/76355416 题目是求长度为m的序列 那我们可以看成是从根节点出发往下走了m步之后到达字典树上的某一个节点,而最后求得就是从根节点走了m步之后能够到达的某个节点的种类数和,当然我们在走的时候需要避开病毒,也就是不能到达我们树中被标记过的点。最后就将这个问题转化成了求从根节点出发走m步之后到达任意一个k节点的种类数,可以用矩阵快速幂来求解。
ps:假如有一个矩阵mp[i][j]代表了从i节点走一步走到j节点的种类数,那么我们就用(mp[i][j])^n代表从i节点走n步之后到达j节点的种类数;
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<string> 5 #include<queue> 6 7 using namespace std; 8 typedef long long LL; 9 const int max_tot = 100010; 10 const int max_size = 4; 11 const LL mod = 100000; 12 char s[100]; 13 struct mac { 14 LL a[110][110];//由于只有小于等于10个单词且每个单词长度不超过10,所以最多有100个节点 15 int len; 16 mac() { 17 len = 0; 18 memset(a, 0, sizeof(a)); 19 } 20 mac operator*(const mac &c)const { 21 mac t; t.len = len; 22 for (int i = 0; i < len; i++) 23 for (int j = 0; j < len; j++) { 24 t.a[i][j] = 0; 25 for (int k = 0; k < len; k++) 26 t.a[i][j] += a[i][k] * c.a[k][j]; 27 t.a[i][j] %= mod; 28 } 29 return t; 30 } 31 }; 32 mac Pow(mac a, int b){ 33 mac ans; ans.len = a.len; 34 for (int i = 0; i < a.len; i++)ans.a[i][i] = 1; 35 while (b) { 36 if (b & 1) 37 ans = ans*a; 38 a = a * a; 39 b >>= 1; 40 } 41 return ans; 42 } 43 struct AC { 44 int trie[max_tot][max_size]; 45 int val[max_tot]; 46 int fail[max_tot], last[max_tot]; 47 int size; 48 void Clear() 49 { 50 memset(trie[0], 0, sizeof(trie[0])); 51 size = 1; 52 } 53 int idx(char x) { 54 if (x == 'A')return 0; 55 if (x == 'C')return 1; 56 if (x == 'G')return 2; 57 if (x == 'T')return 3; 58 } 59 void insert(char *str) { 60 int k = 0; 61 for (int i = 0; str[i]; i++) { 62 int x = idx(str[i]); 63 if (!trie[k][x]) { 64 memset(trie[size], 0, sizeof(trie[size])); 65 val[size] = 0; 66 trie[k][x] = size++; 67 } 68 k = trie[k][x]; 69 } 70 val[k] = 1; 71 } 72 void GetFail() 73 { 74 queue<int>Q; 75 fail[0] = 0; int k = 0; 76 for (int i = 0; i < max_size; i++) {//计算第一层的fail指针跟last指针 77 k = trie[0][i]; 78 if (k) { 79 Q.push(k); 80 fail[k] = 0; 81 last[k] = 0; 82 } 83 } 84 while (!Q.empty()) { 85 int r = Q.front(); Q.pop(); 86 for (int i = 0; i < max_size; i++) { 87 k = trie[r][i]; 88 if (!k) { 89 trie[r][i] = trie[fail[r]][i]; 90 val[r] = val[r] || val[fail[r]]; 91 continue; 92 } 93 Q.push(k); 94 int v = fail[r]; 95 while (v && !trie[v][i])v = fail[k]; 96 fail[k] = trie[v][i]; 97 last[k] = (val[fail[k]] ? fail[k] : last[fail[k]]); 98 } 99 } 100 } 101 }ac; 102 int main() 103 { 104 ios::sync_with_stdio(false); 105 int n, m; 106 while (cin>>n>>m) { 107 ac.Clear(); 108 for (int i = 1; i <= n; i++) { 109 cin >> s; 110 ac.insert(s); 111 } 112 ac.GetFail(); 113 mac ans; ans.len = ac.size; 114 for (int i = 0; i < ac.size; i++) { 115 for (int j = 0; j < max_size; j++) { 116 int u = ac.trie[i][j]; 117 if (!ac.val[u])ans.a[i][u]++; 118 } 119 } 120 ans = Pow(ans, m); 121 LL sum = 0; 122 for (int i = 0; i < 110; i++) 123 sum = (sum + ans.a[0][i]) % mod; 124 cout << sum << endl; 125 } 126 return 0; 127 }