题目链接:点击打开链接
题意描述:给m字符串,这m个字符串是带有病毒的DNA。然后问一个长度为n的字符串不带有任何病毒有多少中可能?所有字符串之后ACGT这几个字符串组成
解题思路:AC自动机+矩阵快速幂
前置内容:邻接矩阵幂的含义:点击打开链接
分析:首先根据题意先建一个AC自动机,其实AC自动机本身就是一张图,AC自动机中的每个结点就相当于图中的顶点,每个转移A、C、G、T就相当于一条边;根据邻接矩阵幂的含义,我们发现求长度为n的字符串的个数就相当于从起点在图中走n步所能到达的所点的方案数的和,而n又很大,我们可以使用矩阵快速幂;但是本题有限制就是不能带有某些字符串,言外之意就是图中有些节点不能经过,根据AC自动机中的end[i]我们可以将这种情况去掉
代码:
#include <cstdio>
#include <cstring>
#include <queue>
#define MOD 100000
typedef long long ll;
using namespace std;
struct Matrix{
ll m[110][110];
int L;
Matrix(int len){
L=len;
for(int i=0;i<L;++i)
for(int j=0;j<L;++j)
m[i][j]=0;
}
};
Matrix mat(Matrix a,Matrix b){
Matrix c(a.L);
for(int i=0;i<c.L;++i)
for(int j=0;j<c.L;++j){
for(int k=0;k<c.L;++k){
c.m[i][j]+=(a.m[i][k]*b.m[k][j]);
c.m[i][j]%=MOD;
}
}
return c;
}
Matrix doexpmat(Matrix a,int num){
Matrix t(a.L);
for(int i=0;i<t.L;++i)
t.m[i][i]=1;
while(num){
if(num&1) t=mat(a,t);
num=num>>1;
a=mat(a,a);
}
return t;
}
struct Trie{
int next1[110][4],fail[110];
bool end1[110];
int root,L;
int newnode(){
for(int i=0;i<4;++i) next1[L][i]=-1;
end1[L++]=false;
return L-1;
}
void init(){ L=0; root=newnode(); }
int getchs(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 insertnode(char* str){
int now=root;
int len=strlen(str);
for(int i=0;i<len;++i){
int to=getchs(str[i]);
if(next1[now][to]==-1)
next1[now][to]=newnode();
now=next1[now][to];
}
end1[now]=true;
}
void build(){
fail[root]=root;
queue<int> q;
for(int i=0;i<4;++i){
if(next1[root][i]==-1) next1[root][i]=root;
else{
fail[next1[root][i]]=root;
q.push(next1[root][i]);
}
}
while(!q.empty()){
int now=q.front(); q.pop();
if(end1[fail[now]]==true)///注意
end1[now]=true;
for(int i=0;i<4;++i){
if(next1[now][i]==-1) next1[now][i]=next1[fail[now]][i];
else {
fail[next1[now][i]]=next1[fail[now]][i];
q.push(next1[now][i]);
}
}
}
}
Matrix getMatrix(){
Matrix res = Matrix(L);
for(int i=0;i<L;i++) for(int j=0;j<4;++j)
if(!end1[next1[i][j]]) res.m[i][next1[i][j]]++;
return res;
}
};
int m,n;
char st[20];
Trie ac;
int main(){
while(scanf("%d%d",&m,&n)!=EOF){
ac.init();
for(int i=0;i<m;++i){ scanf("%s",st); ac.insertnode(st); };
ac.build();
Matrix a=ac.getMatrix();
a=doexpmat(a,n);
int ans=0;
for(int i=0;i<a.L;i++)
ans=(ans+(int)a.m[0][i])%MOD;
printf("%d\n",ans);
}
return 0;
}