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 }

 

posted @ 2015-06-24 21:54  jasaiq  阅读(162)  评论(0编辑  收藏  举报