题目大意:
给出N个串,问在长度为L的所有串中,不包含任一已知串的个数有多少个。
思路分析:
已知一个矩阵A,A[i][j] 表示 节点i 到 节点 j 有一条变可以到达的方法数。
那么A^2 ,这个矩阵的 [i][j] 就代表这个节点 i 到节点 j 有两条边可以到达的方法数。
那么知道这个结论,我们要做的就是求一个节点到另外一个节点,要经过L条变(对应这长度为L的单词),而又要满足任意一条边都不能经过已知单词。
所以我们要用到ac自动机处理出所有已知的单词,在ac自动机上得到这个矩阵,使得任意两个节点之间都不是已知单词的结尾,我们才连一条边。
还要理解AC自动机的一点,就是在失配的时候,也就是要得到fail的时候,其实可以抽象成你fail的下一个节点就是这个节点的next节点。可以看成是一个单词。
那么也就要加上代码中标记上的那个注释上的判断。可以稍微想一想。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 105
#define maxn 10005
using namespace std;
typedef long long ll;
const int mod = 100000;
int rev[180];
const char tab = 0;
const int max_next = 4;
int next[maxn][max_next],fail[maxn],num[maxn],siz;
int newnode()
{
for(int i=0;i<max_next;i++)
next[siz][i]=0;
fail[siz]=num[siz]=0;
return siz++;
}
void init()
{
siz=0;
newnode();
}
void Insert(char *s,int len)
{
int p=0;
for(int i=0;i<len;i++)
{
int &x=next[p][rev[s[i]]];
p=x?x:x=newnode();
}
num[p]++;
}
void acbuild()
{
queue<int>Q;
Q.push(0);
while(!Q.empty())
{
int temp=Q.front();
Q.pop();
for(int i=0;i<max_next;i++)
{
int v=next[temp][i];
if(v==0)next[temp][i]=next[fail[temp]][i];
else Q.push(v);
if(temp!=0)fail[v]=next[fail[temp]][i];
if(num[next[fail[temp]][i]])num[next[temp][i]]++;//---------
}
}
}
struct matrix
{
int r,c;
ll data[N][N];
matrix(){}
matrix(int _r,int _c):r(_r),c(_c){}
friend matrix operator * (const matrix A,const matrix B)
{
matrix res;
res.r=A.r;res.c=B.c;
memset(res.data,0,sizeof res.data);
for(int i=0;i<A.r;i++)
{
for(int j=0;j<B.c;j++)
{
for(int k=0;k<A.c;k++)
{
if(A.data[i][k] && B.data[k][j]){
res.data[i][j]+=A.data[i][k]*B.data[k][j];
res.data[i][j]%=mod;
}
}
}
}
return res;
}
friend matrix operator + (const matrix A,const matrix B)
{
matrix res;
res.r=A.r;res.c=A.c;
memset(res.data,0,sizeof res.data);
for(int i=0;i<A.r;i++)
{
for(int j=0;j<A.c;j++)
{
res.data[i][j]=A.data[i][j]+B.data[i][j];
res.data[i][j]%=mod;
}
}
return res;
}
friend matrix operator - (const matrix A,const matrix B)
{
matrix res;
res.r=A.r;res.c=A.c;
memset(res.data,0,sizeof res.data);
for(int i=0;i<A.r;i++)
{
for(int j=0;j<A.c;j++)
{
res.data[i][j]=A.data[i][j]-B.data[i][j];
res.data[i][j]=(res.data[i][j]%mod+mod)%mod;
}
}
return res;
}
friend matrix operator ^ (matrix A,int n)
{
matrix res;
res.r=A.r;res.c=A.c;
memset(res.data,0,sizeof res.data);
for(int i=0;i<A.r;i++)res.data[i][i]=1;
while(n)
{
if(n&1)res=res*A;
A=A*A;
n>>=1;
}
return res;
}
void print()
{
for(int i=0;i<r;i++)
{
for(int j=0;j<c;j++)
printf("%d ",data[i][j]);
puts("");
}
}
}E,zero;
char word[10005];
int main()
{
for(int i=0;i<N;i++)
E.data[i][i]=1;
rev['A']=0;
rev['C']=1;
rev['G']=2;
rev['T']=3;
int n,L;
while(scanf("%d%d",&n,&L)!=EOF)
{
init();
for(int i=1;i<=n;i++)
{
scanf("%s",word);
Insert(word,strlen(word));
}
acbuild();
matrix origin(siz,siz);
for(int i=0;i<siz;i++)
{
if(!num[i])
{
for(int d=0;d<4;d++)
{
if(!num[next[i][d]])
{
origin.data[i][next[i][d]]++;
}
}
}
}
origin= origin^L;
int ans=0;
for(int i=0;i<siz;i++)
{
if(!num[i])
ans=(ans+origin.data[0][i])%mod;
}
printf("%d\n",ans);
}
return 0;
}