题目大意:某些特定的DNA片段被认为是携带遗传病的序列,现在给出m个带有遗传病的DNA序列,让找出有多少种长度为n的DNA序列不包含任何的遗传病。
分析:首先,我们知道,对于一个图G的邻接矩阵matrix[ i ][ j ]来说,其值表示的是从节点i走到节点j走一步有多少种不同的走法;对于matrix^2 [ i ][ j ]来说,表示是从节点i到节点j走两步一共有多少种不同的走法。
那么对于这道题,我们可以把AC自动机建立的tire树化为tire图,求出该图的邻接矩阵之后问题就变为了:从某一节点不经过图中固定的m个节点走n步共有多少种走法。
这样以来,问题就变为了矩阵连乘问题了:我们只需算出该矩阵的n次方,然后把第一行的值相加就可以了,可以用费小马定理快速求出矩阵的n次幂。
参考链接:点击打开链接
为了便于构造邻接矩阵,直接用数组来纪录tire树了。
实现代码如下:
#include <cstdio> #include <iostream> #include <cstring> using namespace std; #define mod 100000 #define maxn 128 typedef struct { int num; int fail; int next[4]; }Tire; Tire tire[maxn]; int que[maxn]; int size; int A[maxn][maxn],R[maxn][maxn]; int m,n; char dna[11]; int change(char c) { int cnt; switch(c) { case 'A':cnt=0;break; case 'C':cnt=1;break; case 'G':cnt=2;break; case 'T':cnt=3; } return cnt; } void insert(char *str) { int cnt=1; while(*str) { int temp=change(*str++); if(!tire[cnt].next[temp]) tire[cnt].next[temp]=++size; cnt=tire[cnt].next[temp]; } tire[cnt].num++; } void build_fail() { int head=0,tail=0; que[head++]=1; while(head!=tail) { int cnt=que[tail++]; for(int i=0;i<4;i++) { if(!tire[cnt].next[i]) continue; if(cnt==1) tire[ tire[cnt].next[i] ].fail=1; else { int temp=tire[cnt].fail; while(temp&&!tire[temp].next[i]) temp=tire[temp].fail; tire[ tire[cnt].next[i] ].fail=temp?tire[temp].next[i]:1; if(temp&&tire[ tire[temp].next[i] ].num) tire[ tire[cnt].next[i] ].num++; } que[head++]=tire[cnt].next[i]; } } } void get_tire_matrix() { for(int i=1;i<=size;i++) { if(tire[i].num) continue; for(int j=0;j<4;j++) { if(tire[i].next[j]&&!tire[ tire[i].next[j] ].num) A[i][ tire[i].next[j] ]++; else if(!tire[i].next[j]) { if(i==1) A[1][1]++; else { int k=i; while(!tire[k].next[j]&&k!=1) k=tire[k].fail; if(tire[k].next[j]&&!tire[ tire[k].next[j] ].num) A[i][ tire[k].next[j] ]++; else if(!tire[k].next[j]&&k==1) A[i][1]++; } } } } } void mul_matrix(int a[maxn][maxn],int b[maxn][maxn]) { long long temp; int c[maxn][maxn]={0}; for(int i=1;i<=size;i++) for(int j=1;j<=size;j++) for(int k=1;k<=size;k++) { temp=(long long)a[i][k]*b[k][j]; if(temp>=mod) temp%=mod; c[i][j]+=temp; } for(int i=1;i<=size;i++) for(int j=1;j<=size;j++) a[i][j]=c[i][j]; } void quick_mod() { for(int i=1;i<=size;i++) R[i][i]=1; while(n) { if(n&1) mul_matrix(R,A); mul_matrix(A,A); n>>=1; } } int main() { scanf("%d%d",&m,&n); size=1; while(m--) { scanf("%s",dna); insert(dna); } build_fail(); get_tire_matrix(); quick_mod(); int ans=0; for(int i=1;i<=size;i++) { ans+=R[1][i]; if(ans>=mod) ans%=mod; } printf("%d\n",ans); return 0; }
#include <iostream> #include <stdio.h> #include <algorithm> #include <string.h> #include <queue> using namespace std; const int MOD=100000; struct Matrix { int mat[110][110],n; Matrix(){} Matrix(int _n) { n = _n; for(int i=0;i<n;i++) for(int j=0;j<n;j++) mat[i][j]=0; } Matrix operator *(const Matrix &b)const { Matrix ret=Matrix(n); for(int i=0;i<n;i++) for(int j=0;j<n;j++) for(int k=0;k<n;k++) { int tmp=(long long)mat[i][k]*b.mat[k][j]%MOD; ret.mat[i][j]=(ret.mat[i][j]+tmp)%MOD; } return ret; } }; struct Trie { int next[110][4],fail[110]; bool end[110]; int root,L; int newnode() { for(int i=0;i<4;i++) next[L][i]=-1; end[L++]=false; return L-1; } void init() { L=0; root=newnode(); } int getch(char ch) { switch(ch) { case 'A': return 0; break; case 'C': return 1; break; case 'G': return 2; break; case 'T': return 3; break; } } void insert(char s[]) { int len=strlen(s); int now=root; for(int i = 0;i < len;i++) { if(next[now][getch(s[i])] == -1) next[now][getch(s[i])] = newnode(); now = next[now][getch(s[i])]; } end[now]=true; } void build() { queue<int>Q; for(int i = 0;i < 4;i++) if(next[root][i] == -1) next[root][i] = root; else { fail[next[root][i]] = root; Q.push(next[root][i]); } while(!Q.empty()) { int now = Q.front(); Q.pop(); if(end[fail[now]]==true) end[now]=true; for(int i = 0;i < 4;i++) { if(next[now][i] == -1) next[now][i] = next[fail[now]][i]; else { fail[next[now][i]] = next[fail[now]][i]; Q.push(next[now][i]); } } } } Matrix getMatrix() { Matrix res = Matrix(L); for(int i=0;i<L;i++) for(int j=0;j<4;j++) if(end[next[i][j]]==false) res.mat[i][next[i][j]]++; return res; } }; Trie ac; char buf[20]; Matrix pow_M(Matrix a,int n) { Matrix ret = Matrix(a.n); for(int i = 0; i < ret.n; i++) ret.mat[i][i]=1; Matrix tmp=a; while(n) { if(n&1)ret=ret*tmp; tmp=tmp*tmp; n>>=1; } return ret; } int main() { int n,m; while(scanf("%d%d",&n,&m) != EOF) { ac.init(); for(int i=0;i<n;i++) { scanf("%s",buf); ac.insert(buf); } ac.build(); Matrix a=ac.getMatrix(); a=pow_M(a,m); int ans=0; for(int i=0;i<a.n;i++) { ans=(ans+a.mat[0][i])%MOD; } printf("%d\n",ans); } return 0; }