题意:
(只含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 }