【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("\n");
 28     // }
 29     // printf("\n");
 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\n",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("\n");
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\n",MatrixPow(n));
127     return 0;
128 }
poj2778(以前的代码)

 

posted @ 2016-07-14 10:47  拦路雨偏似雪花  阅读(234)  评论(0编辑  收藏  举报