题目大意:某些特定的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;
}