一、题目
二、解法
观察数据范围,发现这道题需要对数据分类讨论。
0x01 l<=100
在 自动机上 ,设 为长度为 ,在自动机上匹配到了点 ,暴力转移即可。
0x02 l<=1e8 且 基本词汇长度不超过2
这种数据最大的特点就是
只可能从
转移过来,并且数据范围提示你要用矩阵乘法。
构造方法如图所示,左边是转移矩阵,右边是初始矩阵。根据转移方程:
,我们把转移矩阵的对应位加一(需要对长度讨论,比如长度为
时,
),表示
转移到
。最开始的
特殊算就行了,具体操作可以参考我的代码。
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int M = 105;
const int MOD = 1e9+7;
int read()
{
int x=0,flag=1;
char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,l,ans,to[M];
char s[M][M],t[M];
void mod(int &x)
{
x%=MOD;
}
struct Matrix
{
int n,m,a[2*M][2*M];
Matrix()
{
n=m=0;
memset(a,0,sizeof a);
}
Matrix operator * (const Matrix &B) const
{
Matrix r;
r.n=n;
r.m=B.m;
for(int i=0; i<=n; i++)
for(int j=0; j<=m; j++)
for(int k=0; k<=B.m; k++)
r.a[i][k]=(r.a[i][k]+1ll*a[i][j]*B.a[j][k])%MOD;
return r;
}
Matrix qkpow(int b)
{
Matrix res,a=*this;
res.n=res.m=a.n;
for(int i=0; i<=a.n; i++) res.a[i][i]=1;
while(b>0)
{
if(b&1) res=res*a;
a=a*a;
b>>=1;
}
return res;
}
void print()
{
for(int i=0; i<=n; i++,puts(""))
for(int j=0; j<=m; j++)
printf("%d ",a[i][j]);
}
} F,A;
struct automaton
{
int cnt,c[M][26],fail[M],val[M],f[M][M];
void ins(char *s)
{
int len=strlen(s),now=0;
for(int i=0; i<len; i++)
{
int v=s[i]-'a';
if(!c[now][v]) c[now][v]=++cnt;
now=c[now][v];
}
val[now]=1;
}
void build()
{
queue<int> q;
for(int i=0; i<26; i++) if(c[0][i]) q.push(c[0][i]);
while(!q.empty())
{
int t=q.front();
q.pop();
val[t]|=val[fail[t]];
for(int i=0; i<26; i++)
if(c[t][i]) fail[c[t][i]]=c[fail[t]][i],q.push(c[t][i]);
else c[t][i]=c[fail[t]][i];
}
}
void dp1()
{
f[0][0]=1;
for(int i=0; i<l; i++)
for(int j=0; j<=cnt; j++)
for(int k=1; k<=n; k++)
{
int now=j,len=strlen(s[k]);
if(i+len>l) continue;
for(int o=0; o<len; o++)
{
now=c[now][s[k][o]-'a'];
if(val[now]) goto In;
}
mod(f[i+len][now]+=f[i][j]);
In:
;
}
for(int i=0; i<=cnt; i++)
mod(ans+=f[l][i]);
printf("%d\n",ans);
}
void dp2()
{
A.n=A.m=F.n=2*cnt+1;
for(int i=0; i<=cnt; i++)
for(int j=1; j<=n; j++)
{
if(val[i]) continue;
int now=i,len=strlen(s[j]);
for(int k=0; k<len; k++)
{
now=c[now][s[j][k]-'a'];
if(val[now]) goto In;
}
if(len==1) A.a[now][i]++;
else A.a[now][i+cnt+1]++;
In:
;
}
for(int i=0; i<=cnt; i++)
A.a[i+cnt+1][i]=1;
for(int i=1; i<=n; i++)
{
int now=0,len=strlen(s[i]);
if(len>1) continue;
for(int j=0; j<len; j++)
{
now=c[now][s[i][j]-'a'];
if(val[now]) break;
}
if(!val[now]) F.a[now][0]++;
}
F.a[cnt+1][0]=1;
F=A.qkpow(l-1)*F;
for(int i=0; i<=cnt; i++)
mod(ans+=F.a[i][0]);
printf("%d\n",ans);
}
} AC;
signed main()
{
n=read();
m=read();
l=read();
for(int i=1; i<=n; i++)
scanf("%s",s[i]);
for(int i=1; i<=m; i++)
{
scanf("%s",t);
AC.ins(t);
}
AC.build();
if(l<=100)
AC.dp1();
else
AC.dp2();
}