POJ 2778 DNA Sequence(AC自动机+矩阵快速幂)
题目链接:http://poj.org/problem?id=2778
题意:有m种DNA序列是有疾病的,问有多少种长度为n的DNA序列不包含任何一种有疾病的DNA序列。(仅含A,T,C,G四个字符)
思路:Trie图的状态转移,用矩阵mat[i][j]来表示从结点i到j只走一步有几种走法,那么mat的n次幂就表示从结点i到j走n步有几种走法,题目要求解的就是从头节点走n步且不包含危险结点的走法。
mat = mat^n ans = (mat[0][0] + mat[0][1] + ... + mat[0][num]) num为结点个数
code:
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <map> 5 using namespace std; 6 const int KIND = 4; 7 const int MAXN = 110; 8 const int MOD = 100000; 9 typedef long long LL; 10 11 struct Trie 12 { 13 int next[MAXN][KIND], fail[MAXN]; 14 bool isExit[MAXN]; 15 int root, L; 16 map<char, int> mp; 17 LL mat[MAXN][MAXN]; 18 LL ret[MAXN][MAXN]; 19 LL tmp[MAXN][MAXN]; 20 int create() 21 { 22 for (int i = 0; i < KIND; ++i) 23 next[L][i] = -1; 24 isExit[L++] = false; 25 return L - 1; 26 } 27 void init() 28 { 29 L = 0; 30 root = create(); 31 mp['A'] = 0; 32 mp['C'] = 1; 33 mp['G'] = 2; 34 mp['T'] = 3; 35 memset(mat, 0, sizeof(mat)); 36 memset(ret, 0, sizeof(ret)); 37 } 38 void insert(char str[]) 39 { 40 int now = root; 41 int len = strlen(str); 42 for (int i = 0; i < len; ++i) 43 { 44 if (-1 == next[now][mp[str[i]]]) 45 next[now][mp[str[i]]] = create(); 46 now = next[now][mp[str[i]]]; 47 } 48 isExit[now] = true; 49 } 50 void build() 51 { 52 queue<int>Q; 53 for (int i = 0; i < KIND; ++i) 54 { 55 if (-1 == next[root][i]) 56 next[root][i] = root; 57 else 58 { 59 fail[next[root][i]] = root; 60 Q.push(next[root][i]); 61 } 62 } 63 while (!Q.empty()) 64 { 65 int now = Q.front(); 66 Q.pop(); 67 if (isExit[fail[now]]) 68 isExit[now] = true; 69 for (int i = 0; i < KIND; ++i) 70 { 71 if (-1 == next[now][i]) 72 next[now][i] = next[fail[now]][i]; 73 else 74 { 75 fail[next[now][i]] = next[fail[now]][i]; 76 Q.push(next[now][i]); 77 } 78 } 79 } 80 } 81 void getMatrix() 82 { 83 for (int i = 0; i < L; ++i) 84 { 85 for (int j = 0; j < KIND; ++j) 86 { 87 if (!isExit[next[i][j]]) 88 ++mat[i][next[i][j]]; 89 } 90 } 91 } 92 void matrixMul(LL mat1[MAXN][MAXN], LL mat2[MAXN][MAXN]) 93 { 94 LL mat3[MAXN][MAXN]; 95 for (int i = 0; i < L; ++i) 96 { 97 for (int j = 0; j < L; ++j) 98 { 99 mat3[i][j] = 0; 100 for (int k = 0; k < L; ++k) 101 mat3[i][j] = (mat3[i][j] + mat1[i][k] * mat2[k][j]) % MOD; 102 } 103 } 104 memcpy(mat1, mat3, sizeof(mat3)); 105 } 106 void matrixQuickMod(LL n) 107 { 108 getMatrix(); 109 for (int i = 0; i < L; ++i) 110 { 111 ret[i][i] = 1; 112 for (int j = 0; j < L; ++j) 113 tmp[i][j] = mat[i][j]; 114 } 115 while (n) 116 { 117 if (n & 1) matrixMul(ret, tmp); 118 matrixMul(tmp, tmp); 119 n >>= 1; 120 } 121 } 122 }; 123 Trie ac; 124 char str[15]; 125 int main() 126 { 127 int m; 128 LL n; 129 while (scanf("%d %lld", &m, &n) != EOF) 130 { 131 ac.init(); 132 for (int i = 0; i < m; ++i) 133 { 134 scanf("%s", str); 135 ac.insert(str); 136 } 137 ac.build(); 138 ac.matrixQuickMod(n); 139 int ans = 0; 140 for (int i = 0; i < ac.L; ++i) 141 ans = (ans + ac.ret[0][i]) % MOD; 142 printf("%d\n", ans); 143 } 144 return 0; 145 }