zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    PHP中的list(),each(),reset()函数应用
    echo(),print(),print_r()
    Math.floor() 与 parseInt()
    利用Node.js轻松创建web服务器
    MySQL中Datetime与Timestamp
    修正正则匹配日期---基于网络未知大神的正则
    数据结构随笔-php实现栈
    数据结构随笔-php实现队列
    Js 获取时间戳
    linux 安装nginx+php+mysql
  • 原文地址:https://www.cnblogs.com/wangrunhu/p/9554116.html
Copyright © 2011-2022 走看看