Description
Data Constraint
Solution
考场上打出了70分,由于没看到100分的长度不超过2,所以与100分失之交臂。
70分显然是打颗AC自动机,在trie树做dp。设f[i][j]表示当前选的字符串长度为i,在trie上第j个点的情况。
我们考虑100分怎么做。看到基本词汇长度长度不超过2,且禁忌词语长度少于100,我们果断想到矩阵乘法。我们把f[i-1],f[i]的方案作为初始矩阵,当前我们要通过乘法转移至f[i+1],f[i],只要想一下构建一个200*200的矩阵就好了。
Code
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll maxn=2e2+1,mo=1e9+7;
struct code{
ll a[maxn][maxn];
}c2,b,c1;
ll f[maxn][maxn],g[maxn][27],p[maxn],c[maxn],v[maxn],d[maxn];
ll n,m,l,i,t,j,k,x,y,z,num,q,bz,ans;
char s[maxn][maxn],s1[maxn];
void make(code x,code y){
memset(c1.a,0,sizeof(c1.a));ll i,j,k;
for (i=0;i<=n;i++)
for (j=0;j<=n;j++){
for (k=0;k<=n;k++)
c1.a[i][j]=c1.a[i][j]+x.a[i][k]*y.a[k][j]%mo;
c1.a[i][j]%=mo;
}
}
void bfs(){
int i=0,j=1;
while (i<j){
x=v[++i];
for (k=0;k<26;k++){
if (!g[x][k]) continue;
y=g[x][k];z=p[x];c[y]+=c[x];
while (z && !g[z][k]) z=p[z];
v[++j]=y;
if (g[z][k] && x) p[y]=g[z][k],c[y]+=c[p[y]];
}
}
}
void dg(){
while (l>1) d[++d[0]]=l%2,l/=2;
c1=c2;
while (d[0])
if (d[d[0]--])make(c1,c1),make(c1,c2);
else make(c1,c1);
}
int main(){
freopen("sorcery.in","r",stdin);freopen("sorcery.out","w",stdout);
scanf("%lld%lld%lld\n",&n,&m,&l);
for (i=1;i<=n;i++)
scanf("%s\n",s[i]+1);
for (i=1;i<=m;i++){
scanf("%s\n",s1+1);x=0;t=strlen(s1+1);
for (j=1;j<=t;j++){
if (!g[x][s1[j]-97]) g[x][s1[j]-97]=++num;
x=g[x][s1[j]-97];
}
c[x]=1;
}
bfs();
if (l<=100){
f[0][0]=1;
for (i=0;i<l;i++)
for (j=0;j<=num;j++){
if (!f[i][j] || c[j]) continue;
for (k=1;k<=n;k++){
t=strlen(s[k]+1);
if (t+i>l) continue;
x=j;bz=1;
for (q=1;q<=t;q++){
while (!g[x][s[k][q]-97] && x) x=p[x];
if (g[x][s[k][q]-97]){
x=g[x][s[k][q]-97];
if (c[x]){
bz=0;break;
}
}
}
if (bz) f[i+t][x]=(f[i+t][x]+f[i][j])%mo;
}
}
for (i=0;i<=num;i++)
ans=(ans+f[l][i])%mo;
printf("%lld\n",ans);
}else{
for (j=0;j<=num;j++){
if (c[j]) continue;
for (k=1;k<=n;k++){
t=strlen(s[k]+1);
x=j;bz=1;
for (q=1;q<=t;q++){
while (!g[x][s[k][q]-97] && x) x=p[x];
if (g[x][s[k][q]-97]){
x=g[x][s[k][q]-97];
if (c[x]){
bz=0;break;
}
}
}
if (bz){
if (t==1) c2.a[j][x]++;
else c2.a[j+num+1][x]++;
}
}
}
for (i=0;i<=num;i++)
c2.a[i][i+num+1]=1;
n=num*2+1;
b.a[0][0]=1;
dg();
make(b,c1);
for (i=0;i<=num;i++)
ans=(ans+c1.a[0][i])%mo;
printf("%lld\n",ans);
}
}