加油 ( •̀ ω •́ )y!

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. 

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. 

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 }
View Code

 

posted @ 2018-08-29 14:33  皮皮虎  阅读(194)  评论(0编辑  收藏  举报