zoukankan      html  css  js  c++  java
  • POJ2778 DNA Sequence(AC自动机+矩阵快速幂)

    题目给m个病毒串,问不包含病毒串的长度n的DNA片段有几个。

    感觉这题好神,看了好久的题解。

    所有病毒串构造一个AC自动机,这个AC自动机可以看作一张有向图,图上的每个顶点就是Trie树上的结点,每个结点都可以看作是某个病毒串的前缀,Trie树的根则是空字符串。

    而从根出发,在AC自动机上跑,经过k次转移到达某个结点,这个结点所代表的病毒串前缀可以看作长度为k的字符串的后缀,如果接下去跑往ATCG四个方向转移,就能到达新的结点,转移到新的长k+1字符串的后缀。

    这样带着一个后缀状态的转移就能绕开病毒串,所以病毒串末尾的结点要标记,后缀存在病毒串的结点也要标记(这个在计算结点fail的时候就能处理),转移时就不能转移到被标记的结点。

    接下来,题目的数据范围是10个长度10的病毒串,所以Trie树中最多101左右个结点,那么AC自动机整个转移就可以构建一张101*101的邻接矩阵,矩阵i行j列的权值是结点i转移到结点j的方案数。

    而进行k次转移,从结点i转移到结点j的方案数是这个矩阵的k次幂,这个结论离散数学的图论有。。

    所以,长度n的字符串的方案数,就是转移n次根结点能到所有结点的方案和就是答案。就是计算矩阵的n次幂,统计根所在行的数字和,n的达到20亿用矩阵快速幂即可。

    (POJ从昨天就挂了。。SCU有原题,多组数据,http://acm.scu.edu.cn/soj/problem.action?id=3030

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<queue>
     4 using namespace std;
     5 int ch[111][4],fail[111],tn;
     6 bool flag[111];
     7 
     8 int idx[128];
     9 void insert(char *s){
    10     int x=0;
    11     for(int i=0; s[i]; ++i){
    12         int y=idx[s[i]];
    13         if(ch[x][y]==0) ch[x][y]=++tn;
    14         x=ch[x][y];
    15     }
    16     flag[x]=1;
    17 }
    18 void init(){
    19     memset(fail,0,sizeof(fail));
    20     queue<int> que;
    21     for(int i=0; i<4; ++i){
    22         if(ch[0][i]) que.push(ch[0][i]);
    23     }
    24     while(!que.empty()){
    25         int now=que.front(); que.pop();
    26         for(int i=0; i<4; ++i){
    27             if(ch[now][i]) que.push(ch[now][i]),fail[ch[now][i]]=ch[fail[now]][i];
    28             else ch[now][i]=ch[fail[now]][i];
    29             flag[ch[now][i]]|=flag[ch[fail[now]][i]];
    30         }
    31     }
    32 }
    33 struct Mat{
    34     long long mat[111][111];
    35     Mat(){
    36         memset(mat,0,sizeof(mat));
    37     }
    38 };
    39 Mat operator*(const Mat &m1,const Mat &m2){
    40     Mat m;
    41     for(int i=0; i<=tn; ++i){
    42         for(int j=0; j<=tn; ++j){
    43             for(int k=0; k<=tn; ++k){
    44                 m.mat[i][j]+=m1.mat[i][k]*m2.mat[k][j];
    45                 m.mat[i][j]%=100000;
    46             }
    47         }
    48     }
    49     return m;
    50 }
    51 int main(){
    52     idx['A']=0; idx['C']=1; idx['T']=2; idx['G']=3;
    53     char str[11];
    54     int m,n;
    55     while(~scanf("%d%d",&m,&n)){
    56         tn=0;
    57         memset(flag,0,sizeof(flag));
    58         memset(ch,0,sizeof(ch));
    59         while(m--){
    60             scanf("%s",str);
    61             insert(str);
    62         }
    63         init();
    64         Mat e,x;
    65         for(int i=0; i<=tn; ++i) e.mat[i][i]=1;
    66         for(int i=0; i<=tn; ++i){
    67             if(flag[i]) continue;
    68             for(int j=0; j<4; ++j){
    69                 if(flag[ch[i][j]]) continue;
    70                 ++x.mat[i][ch[i][j]];
    71             }
    72         }
    73         while(n){
    74             if(n&1) e=e*x;
    75             x=x*x;
    76             n>>=1;
    77         }
    78         long long res=0;
    79         for(int i=0; i<=tn; ++i){
    80             res+=e.mat[0][i];
    81             res%=100000;
    82         }
    83         printf("%lld
    ",res);    
    84     }
    85     return 0;
    86 }
  • 相关阅读:
    还在使用golang 的map 做Json编码么?
    Golang 性能测试(2) 性能分析
    golang 性能测试 (1) 基准性能测试
    消息队列 NSQ 源码学习笔记 (五)
    消息队列 NSQ 源码学习笔记 (四)
    消息队列 NSQ 源码学习笔记 (三)
    消息队列 NSQ 源码学习笔记 (二)
    消息队列 NSQ 源码学习笔记 (一)
    你不知道的空格
    Supervisor 使用和进阶4 (Event 的使用)
  • 原文地址:https://www.cnblogs.com/WABoss/p/5167101.html
Copyright © 2011-2022 走看看