传送门:bzoj4861
题解
首先把忌讳词建成AC自动机,所有串的 e n d end end结点和可以通过跳 f a i l fail fail链到一个 e n d end end结点的点都不能走到( g e t f a i l getfail getfail时预处理即可)。
当
L
≤
100
L\leq 100
L≤100时,考虑在AC自动机上DP:
DP算是比较套路的了。
设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示已经选择了
i
i
i个字符,走到了自动机上
j
j
j结点的方案数,有
f
[
j
+
s
z
k
]
[
t
r
a
n
s
[
j
]
[
k
]
]
+
=
f
[
i
]
[
j
]
f[j+sz_k][trans[j][k]]+=f[i][j]
f[j+szk][trans[j][k]]+=f[i][j]
其中
k
k
k枚举的是基本词汇,
s
z
k
sz_k
szk是串长,
t
r
a
n
s
[
j
]
[
k
]
trans[j][k]
trans[j][k]表示在
j
j
j结点时再接上串
k
k
k后会走到的结点。
设初始值
f
[
0
]
[
0
]
=
1
f[0][0]=1
f[0][0]=1后
O
(
n
3
)
D
P
O(n^3)DP
O(n3)DP即可。
当
L
>
100
L>100
L>100时,
D
P
DP
DP的复杂度显然不可接受,但考虑到
l
e
n
≤
2
len\leq 2
len≤2,
也就是一个最多关乎
i
−
1
,
i
−
2
i-1,i-2
i−1,i−2两项的线性递推式,直接矩阵快速幂即可。
复杂度
O
(
n
3
l
o
g
L
)
O(n^3logL)
O(n3logL)
代码
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7,N=110;
int n,m,L,ans,cnt,trans[N][N];
int sz[N],len,mx,ed[N];
char s[N][N],t[N];
inline void ad(int &x,int y){x+=y;if(x>=mod) x-=mod;}
struct AC{
queue<int>Q;
int ch[N][26],f[N];
inline void ins(char *s)
{
int i,alp,u=0;len=strlen(s);
for(i=0;i<len;++i){
alp=s[i]-'a';
if(!ch[u][alp]) ch[u][alp]=++cnt;
u=ch[u][alp];
}
ed[u]=1;
}
void getfail()
{
int i,x,y,z,u;
for(i=0;i<26;++i){
x=ch[0][i];if(x) Q.push(x);
}
for(;!Q.empty();){
x=Q.front();Q.pop();y=f[x];
for(i=0;i<26;++i){
z=ch[x][i];u=ch[y][i];
if(!z) {ch[x][i]=u;continue;}
f[z]=u;ed[z]|=ed[u];Q.push(z);
}
}
}
inline void getrans(int id,char *s)
{
int i,j,u;len=strlen(s);
mx=max(mx,len);sz[id]=len;
for(i=0;i<len;++i) s[i]-='a';
for(i=0;i<=cnt;++i) if(!ed[i]){
u=i;
for(j=0;j<len;++j){
u=ch[u][(int)s[j]];
if(ed[u]) {u=-1;break;}
}
trans[i][id]=u;
}
}
}ac;
namespace pA{
int dp[N][N];
void solve(){
int i,j,k,res;
dp[0][0]=1;
for(i=0;i<L;++i)
for(j=0;j<=cnt;++j)
if(dp[i][j]){
res=dp[i][j];
for(k=1;k<=n;++k)
if((~trans[j][k]) && i+sz[k]<=L)
ad(dp[i+sz[k]][trans[j][k]],res);
}
for(i=0;i<=cnt;++i) ad(ans,dp[L][i]);
printf("%d",ans);
}
}
namespace pB{
int lim;
struct Mat{
int v[N<<1][N<<1];
inline void itia(){for(int i=0;i<=lim;++i) v[i][i]=1;}
}g,e,re;
inline void Mul(Mat &x,Mat y)
{
int i,j,k,res;
for(i=0;i<=lim;++i)
for(j=0;j<=lim;++j){
res=0;
for(k=0;k<=lim;++k)
ad(res,1ll*x.v[i][k]*y.v[k][j]%mod);
re.v[i][j]=res;
}
for(i=0;i<=lim;++i)
for(j=0;j<=lim;++j)
x.v[i][j]=re.v[i][j];
}
void maker()
{
int i,j;
if(mx==1){
lim=cnt;
for(i=0;i<=cnt;++i)
if(!ed[i])
for(j=1;j<=n;++j)
if(~trans[i][j])
g.v[i][trans[i][j]]++;
}else{
lim=(cnt<<1)+1;
for(i=0;i<=cnt;++i)
for(j=1;j<=n;++j)
if(~trans[i][j]){
if(sz[j]==1)
g.v[i][trans[i][j]]++;
else
g.v[i+cnt+1][trans[i][j]]++;
}
for(i=0;i<=cnt;++i) g.v[i][i+cnt+1]++;
}
}
void solve()
{
int i,j;
maker();e.itia();
for(;L;L>>=1,Mul(g,g))
if(L&1) Mul(e,g);
for(i=0;i<=cnt;++i){
ad(ans,e.v[0][i]);
}
printf("%d",ans);
}
}
int main(){
int i;scanf("%d%d%d",&n,&m,&L);
for(i=1;i<=n;++i) scanf("%s",s[i]);
for(i=1;i<=m;++i){scanf("%s",t);ac.ins(t);}
ac.getfail();memset(trans,0xff,sizeof(trans));
for(i=1;i<=n;++i) ac.getrans(i,s[i]);
if(L<=100) pA::solve();
else pB::solve();
return 0;
}