当
l
≤
100
l\le 100
l≤100时
显然的自动机上
d
p
dp
dp就完了
当
l
≤
1
e
8
l\le1e8
l≤1e8时直接
d
p
dp
dp显然是不行的
但是发现基本串长度不大于二
考虑矩乘优化
a
[
i
]
[
j
]
a[i][j]
a[i][j]表示有几个基本串使得在自动机上
i
i
i走到
j
j
j
如果所有串长相同就可以直接快速幂了
但是串长有
1
1
1有
2
2
2
不同长度不好处理拼起来的情况
设
A
1
A_1
A1表示长度为1的串的转移矩阵
A
2
A_2
A2为长度为2的
考虑构造矩阵
[ 0 A 2 I A 1 ] \begin{bmatrix} 0&A_2\\ I &A_1 \end{bmatrix} [0IA2A1]
这样的转移矩阵就可以了
#include<bits/stdc++.h>
using namespace std;
#define gc getchar
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
int n,m,l;
const int N=55,M=105;
const int mod=1e9+7;
inline int add(int a,int b){return (a+=b)>=mod?a-=mod:a;}
inline void Add(int &a,int b){(a+=b)>=mod?a-=mod:0;}
inline int dec(int a,int b){return (a-=b)<0?a+=mod:a;}
inline void Dec(int &a,int b){(a-=b)<0?a+=mod:0;}
inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int ksm(int a,int b,int res=1){
for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));return res;
}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
namespace Ac{
int nxt[M][26],tot,fail[M],ed[M];
inline void insert(char *s){
int p=0;
for(int i=1,len=strlen(s+1);i<=len;i++){
int c=s[i]-'a';
if(!nxt[p][c])nxt[p][c]=++tot;
p=nxt[p][c];
}
ed[p]++;
}
queue<int> q;
inline void build(){
for(int i=0;i<26;i++){
if(nxt[0][i])fail[nxt[0][i]]=0,q.push(nxt[0][i]);
}
while(!q.empty()){
int p=q.front();q.pop();
for(int c=0;c<26;c++){
int v=nxt[p][c];
if(!v)nxt[p][c]=nxt[fail[p]][c];
else fail[v]=nxt[fail[p]][c],q.push(v);
}
ed[p]+=ed[fail[p]];
}
}
inline int go(int p,char *s){
if(ed[p])return -1;
for(int i=1,len=strlen(s+1);i<=len;i++){
int c=s[i]-'a';
p=nxt[p][c];
if(ed[p])return -1;
}
return p;
}
}
using namespace Ac;
char s[N][M],t[N][M];
int len[N];
namespace solve1{
int f[M][M];
inline void main(){
f[0][0]=1;
for(int i=0;i<l;i++)
for(int j=0;j<=tot;j++)
for(int k=1;k<=n;k++)
if(i+len[k]<=l){
int p=go(j,s[k]);
if(p!=-1)
Add(f[i+len[k]][p],f[i][j]);
}
int res=0;
for(int i=0;i<=tot;i++)Add(res,f[l][i]);
cout<<res<<'\n';
}
}
namespace solve2{
int lim;
struct mat{
int a[M*2][M*2];
mat(){memset(a,0,sizeof(a));}
friend inline mat operator *(const mat &a,const mat &b){
mat c=mat();
for(int i=0;i<=lim;i++)
for(int k=0;k<=lim;k++)
for(int j=0;j<=lim;j++)
Add(c.a[i][j],mul(a.a[i][k],b.a[k][j]));
return c;
}
}ret,ans;
inline mat ksm(mat a,int b,mat res){
for(;b;b>>=1,a=a*a)if(b&1)res=res*a;
return res;
}
inline void main(){
lim=tot*2+1;
for(int i=0;i<=tot;i++)ret.a[i+tot+1][i]=1;
for(int i=0;i<=tot;i++)
for(int j=1;j<=n;j++){
if(len[j]==2){
int p=go(i,s[j]);
if(p!=-1)ret.a[i][p+tot+1]++;
}
}
for(int i=0;i<=tot;i++)
for(int j=1;j<=n;j++){
if(len[j]==1){
int p=go(i,s[j]);
if(p!=-1)ret.a[i+tot+1][p+tot+1]++;
}
}
ret=ksm(ret,l-1,ret);
ans.a[0][tot+1]=1;
ans=ans*ret;
int res=0;
for(int i=0;i<=tot;i++)
Add(res,ans.a[0][i+tot+1]);
cout<<res;
}
}
int main(){
n=read(),m=read(),l=read();
for(int i=1;i<=n;i++)scanf("%s",s[i]+1),len[i]=strlen(s[i]+1);;
for(int i=1;i<=m;i++)scanf("%s",t[i]+1),insert(t[i]);
build();
if(l<=100)solve1::main();
else solve2::main();
}