zoukankan      html  css  js  c++  java
  • 【poj2778-DNA Sequence】AC自动机+矩阵乘法

    题意:

    (只含AGCT)给定m个病毒串,让你构造一个长度为n的字符串(也只含有AGCT),问有多少种方案。
    n很大:1<=n<=2000000000

    题解:

    用病毒串建立AC自动机(num个节点),然后构建一个num*num的矩阵表示节点i走一步到j有多少种方案。注意:根节点也要算。
    原理:原本是在AC自动机上不断地走,但不能走到病毒末端。该矩阵每格(i,j)表示i走一步到j有多少种方案,n次方就是i走n步到j有多少种方案。
    最后把矩阵[0][i]全部加起来,就是从0出发走n步的全部方案。
    为什么可以只用AC自动机上的节点?因为走其他节点就相当于回到根节点,假设给定一个新构造的串要你判断是不是有病毒串,也不需要除了病毒串以外的节点来判断。
    注意要用longlong。

    代码如下

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<queue>
      6 using namespace std;
      7 
      8 const int N=2000000010,M=15,Mod=100000;
      9 typedef long long LL;
     10 int num,n,m;
     11 char s[20];
     12 queue<int> q;
     13 struct node{
     14     int bk,fail,son[30];
     15 }a[200];
     16 struct nd{
     17     int x,y;
     18     LL z[200][200];
     19 }map;
     20 
     21 // void output(nd p)
     22 // {
     23     // for(int i=0;i<=p.x;i++)
     24     // {
     25         // for(int j=0;j<=p.y;j++)
     26             // printf("%d ",p.z[i][j]);
     27         // printf("
    ");
     28     // }
     29     // printf("
    ");
     30 // }
     31 
     32 int idx(char c)
     33 {
     34     if(c=='A') return 1;
     35     if(c=='T') return 2;
     36     if(c=='C') return 3;
     37     if(c=='G') return 4;
     38 }
     39 
     40 void clear(int x)
     41 {
     42     a[x].fail=a[x].bk=0;
     43     memset(a[x].son,0,sizeof(a[x].son));
     44 }
     45 
     46 void trie(char *c)
     47 {
     48     int x=0,l=strlen(c);
     49     for(int i=0;i<l;i++)
     50     {
     51         int ind=idx(c[i]);
     52         if(!a[x].son[ind])
     53         {
     54             num++;
     55             clear(num);
     56             a[x].son[ind]=num;
     57         }
     58         x=a[x].son[ind];
     59     }
     60     a[x].bk=1;
     61 }
     62 
     63 void buildAC()
     64 {
     65     while(!q.empty()) q.pop();
     66     q.push(0);
     67     while(!q.empty()) 
     68     {
     69         int x=q.front();q.pop();
     70         int fail=a[x].fail;
     71         for(int i=1;i<=4;i++)
     72         {
     73             if(a[x].son[i])
     74             {
     75                 int y=a[x].son[i],z=a[fail].son[i];
     76                 a[y].fail=x ? z : 0;
     77                 a[y].bk|=a[z].bk;
     78                 q.push(y);
     79             }
     80             else a[x].son[i]=a[fail].son[i];
     81             if(!a[a[x].son[i]].bk) map.z[x][a[x].son[i]]++;
     82         }
     83         
     84     }
     85 }
     86 
     87 nd multi(nd u,nd v)
     88 {
     89     nd ans;
     90     ans.x=u.x;ans.y=v.y;
     91     memset(ans.z,0,sizeof(ans.z));
     92     for(int i=0;i<=ans.x;i++)
     93          for(int j=0;j<=ans.y;j++)
     94              for(int k=0;k<=ans.y;k++)
     95                  ans.z[i][j]=(ans.z[i][j]+u.z[i][k]*v.z[k][j])%Mod;
     96     return ans;
     97 }
     98 
     99 LL dp()
    100 {
    101     nd ans;
    102     ans.x=num,ans.y=num;
    103     memset(ans.z,0,sizeof(ans.z));
    104     for(int i=0;i<=num;i++) ans.z[i][i]=1;
    105     while(n)
    106     {
    107         if(n&1) ans=multi(ans,map);
    108         map=multi(map,map);
    109         n/=2;
    110     }
    111     LL sum=0;
    112     for(int i=0;i<=num;i++)
    113         sum=(sum+ans.z[0][i])%Mod;
    114     return sum;
    115 }
    116 
    117 int main()
    118 {
    119     freopen("a.in","r",stdin);
    120     // freopen("a.out","w",stdout);
    121     scanf("%d%d",&m,&n);
    122     for(int i=1;i<=m;i++)
    123     {
    124         scanf("%s",s);
    125         trie(s);
    126     }
    127     map.x=num,map.y=num;
    128     memset(map.z,0,sizeof(map.z));
    129     buildAC();
    130     printf("%I64d
    ",dp());
    131     return 0;
    132 }

    很久以前刚学打过一次,以前的代码如下:

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<queue>
      6 using namespace std;
      7 
      8 const int M=150;
      9 const int MOD=(int)1e5;
     10 char s[M];
     11 int q[M];
     12 long long ay[M][M],sum[M][M];
     13 int n,m,tot,len;
     14 struct node
     15 {
     16     int son[6],cnt,fail,mark;
     17 }t[M];
     18 
     19 void floy()
     20 {
     21     tot=0;
     22     for(int i=1;i<=M;i++)
     23     {
     24         t[i].cnt=0;t[i].mark=0;
     25         for(int j=1;j<=5;j++) t[i].son[j]=0;
     26     }
     27     memset(q,0,sizeof(q));
     28     memset(ay,0,sizeof(ay));
     29     memset(sum,0,sizeof(sum));
     30 }
     31 
     32 void read_trie()
     33 {
     34     tot=0;
     35     int i,j;
     36     scanf("%d%d",&m,&n);
     37     for(i=1;i<=m;i++)
     38     {
     39         int x,ind;
     40         scanf("%s",s+1);
     41         len=strlen(s+1);
     42         x=0;
     43         for(j=1;j<=len;j++)
     44         {
     45             if(s[j]=='A') ind=1;
     46             if(s[j]=='C') ind=2;
     47             if(s[j]=='T') ind=3;
     48             if(s[j]=='G') ind=4;
     49             
     50             if(!t[x].son[ind]) t[x].son[ind]=++tot;
     51             x=t[x].son[ind];
     52             t[x].cnt++;
     53             if(j==len) t[x].mark=1;
     54         }
     55     }
     56 }
     57 
     58 void build_AC()
     59 {
     60     int i,j,x,y;
     61     q[++q[0]]=0;
     62     for(i=1;i<=q[0];i++)
     63     {
     64         x=q[i];
     65         y=t[x].fail;
     66         for(j=1;j<=4;j++)
     67         {
     68             if(t[x].son[j])
     69             {
     70                 //t[t[x].son[j]].fail=t[y].son[j];
     71                 //while(y && !t[y].son[j]) y=t[y].fail;
     72                 t[t[x].son[j]].fail=x?t[y].son[j]:0;
     73                 if(t[t[t[x].son[j]].fail].mark) t[t[x].son[j]].mark=1;
     74                 q[++q[0]]=t[x].son[j];
     75             }
     76             else t[x].son[j]=t[y].son[j];
     77             if(!t[t[x].son[j]].mark) ++ay[x][t[x].son[j]];
     78         }
     79     }
     80 }
     81 
     82 void MatrixMult(long long a[M][M],long long b[M][M])
     83 {
     84     int i,j,k;
     85     long long c[M][M]={0};
     86     for(i=0;i<=tot;i++)
     87      for(j=0;j<=tot;j++)
     88       for(k=0;k<=tot;k++)
     89        c[i][j]+=a[i][k]*b[k][j];
     90     for(i=0;i<=tot;i++)
     91      for(j=0;j<=tot;j++)
     92       a[i][j]=c[i][j]%MOD;
     93 }
     94 
     95 long long MatrixPow(int k)
     96 {
     97     int i,j;
     98     for(i=0;i<=tot;i++)
     99      for(j=0;j<=tot;j++)
    100        sum[i][j]=(i==j);
    101     while(k)
    102     {
    103         if(k&1) MatrixMult(sum,ay);
    104         MatrixMult(ay,ay);
    105         k>>=1;
    106     }
    107     for(int i=0;i<=tot;i++)
    108     {
    109         for(int j=0;j<=tot;j++)
    110             printf("%d ",sum[i][j]);
    111         printf("
    ");
    112     }
    113     long long ans=0;
    114     for(i=0;i<=tot;i++) ans+=sum[0][i];
    115     return ans%MOD;
    116 }
    117 
    118 int main()
    119 {
    120     freopen("a.in","r",stdin);
    121     // freopen("b.out","w",stdout);
    122     floy();
    123     read_trie();
    124     build_AC();
    125     
    126     printf("%I64d
    ",MatrixPow(n));
    127     return 0;
    128 }
    poj2778(以前的代码)
  • 相关阅读:
    关于Vue的路由、脚手架笔记
    个人Vue-1.0学习笔记
    评论发布信息可插入QQ表情
    21 九宫格布局
    20 随机验证码&发表评论
    19 表单验证&上传图片验证
    18 百度换肤&千千音乐盒
    17 JS-图片切换PLUS&关闭小广告
    16 JS应用-图片切换&衣服相册
    15 JS应用-todolist任务
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/5669576.html
Copyright © 2011-2022 走看看