#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string.h>
#include <vector>
#include <queue>
#define mod 100000
#define LL long long //poj2778 ac自动机、矩阵乘法(构建矩阵--关键)
using namespace std;
int k;
struct node //定义静态字典树
{
int isword;
int next[4];
int fail; //定义失败指针
void init()
{
for(int t=0; t<4; ++t)
{
next[t]=0;
}
fail=-1;
isword=0;
}
}a[110];
int check(char c)
{
if(c=='A')return 0;
if(c=='T')return 1;
if(c=='C')return 2;
if(c=='G')return 3;
}
int newnode()
{
a[k].init();
return k;
}
void insert(char *p) //建树
{
int t, j, g=0, h; //g=0表示根
j=strlen(p);
for(t=0; t<j; ++t)
{
h=check(p[t]); //将字符转化为相应的数字
if(!a[g].next[h])
{
a[g].next[h]=newnode();
k++;
}
g=a[g].next[h];
}
a[g].isword=1; //结尾标记
return ;
}
void acAutomation() //构建失败指针fail
{
int t;
queue<int> q;
q.push(0);
while(!q.empty())
{
int s=q.front();
q.pop();
for(t=0; t<4; ++t)
{
if(a[s].next[t]==0)
{
if(s==0)
a[s].next[t]=0;
else a[s].next[t]=a[a[s].fail].next[t]; //不是根节点的话就是s节点的fail所指的节点的next[t]位置
}
else
{
if(s==0)
{
a[a[s].next[t]].fail=0;
}
else
{
int temp=a[s].fail;
while(temp!=-1)
{
if(a[temp].next[t])
{
a[a[s].next[t]].fail=a[temp].next[t];
a[a[s].next[t]].isword|=a[a[temp].next[t]].isword; //a[s].next[t]的最大后缀就是a[a[temp].fail].next[t]前缀,如果a[a[temp].fail].next[t]有标记,则a[s].next[t]也要标上
break;
}
temp=a[temp].fail;
}
if(temp==-1) //到根节点也找不到对应的next
{
a[a[s].next[t]].fail=0;
}
}
q.push(a[s].next[t]);
}
}
}
return ;
}
struct matrix
{
LL b[105][105]; //防止溢出
void init()
{
int t, j;
for(j=0; j<105; ++j)
{
for(t=0; t<105; ++t)
b[j][t]=0;
}
}
matrix operator*(matrix a1) //重载可以减少内存,但速度会慢点
{
matrix q;
q.init();
int j, t, g;
for(j=0; j<k; ++j)
{
for(t=0; t<k; ++t)
{
for(g=0; g<k; ++g)
{
q.b[j][t]+=b[j][g]*a1.b[g][t];
q.b[j][t]%=mod;
}
}
}
return q;
}
}p;
/*
matrix mul(matrix a1, matrix b1) //内存会溢出
{
matrix q;
q.init();
int j, t, g;
for(j=0; j<k; ++j)
{
for(int t=0; t<k; ++t)
{
for(int g=0; g<k; ++g)
{
q.b[j][t]+=a1.b[j][g]*b1.b[g][t];
q.b[j][t]%=mod;
}
}
}
return q;
}
*/
matrix f(int x) //矩阵快速幂
{
matrix q, s=p;
int j, t;
for(j=0; j<k; ++j)
{
for(t=0; t<k; ++t)
{
if(j==t)
q.b[j][t]=1;
else q.b[j][t]=0;
}
}
while(x)
{
if(x&1)
q=q*s;
x=x>>1;
s=s*s;
}
return q;
}
int main()
{
int n, m, t, j, g;
char q[15];
scanf("%d%d", &m, &n);
a[0].init();
k=1;
for(t=0; t<m; ++t)
{
scanf("%s", q);
insert(q);
}
acAutomation();
p.init();
for(j=0; j<k; ++j) //构建无病毒的矩阵
{
if(a[j].isword)continue;
for(t=0; t<4; ++t)
{
g=a[j].next[t];
if(a[g].isword)continue;
p.b[j][g]++;
}
}
matrix result=f(n); //矩阵快速幂
LL ans;
for(t=0, ans=0; t<k; ++t) //统计数目
{
ans+=result.b[0][t];
}
printf("%I64d\n", ans%mod);
return 0;
}
ac自动机、矩阵乘法
最新推荐文章于 2021-12-16 22:38:40 发布