description
solution
先把秘钥建ac自动机,设f[i][j][k][l]表示现在填到第i位,对应ac自动机上j结点,包含k个秘钥,有没有顶上界,枚举下一个填什么转移即可。
code
using namespace std;
int const mn=2 *1e5 +9 ,ml=500 +9 ,mo=1 e9+7 ;
int n,K,pon,fail[ml],cnt[ml],son[ml][10 ],f[ml][ml][12 ][2 ],q[ml] ;
char s [ml],s1[ml],s2[ml];
int min(int x ,int y ){
return (x <y )?x :y ;
}
int calc(char *s ){
int m =strlen(s +1 );
fo(i,0 ,m )fo(j,0 ,pon)fo(k,0 ,K)fo(l,0 ,1 )f[i][j][k][l]=0 ;
f[0 ][0 ][0 ][1 ]=1 ;
fo(i,0 ,m -1 )fo(j,0 ,pon)fo(k,0 ,K)fo(l,0 ,1 )if (f[i][j][k][l]){
int lim=(l)?s [i+1 ]-'0' :9 ;
fo(ii,0 ,lim)
f[i+1 ][son[j][ii]][min(k+cnt[son[j][ii]],K)][l&&(ii==s [i+1 ]-'0' )]
=(f[i+1 ][son[j][ii]][min(k+cnt[son[j][ii]],K)][l&&(ii==s [i+1 ]-'0' )]
+f[i][j][k][l])%mo ;
}
LL ans=0 ;
fo(j,0 ,pon)ans=(ans+f[m ][j][K][0 ]+f[m ][j][K][1 ])%mo ;
return ans;
}
int main(){
freopen("word.in" ,"r" ,stdin);
freopen("word.out" ,"w" ,stdout);
scanf("%d %d " ,&n,&K);
scanf("%s " ,s1+1 );
scanf("%s " ,s2+1 );
fo(cas,1 ,n){
scanf("%s " ,s +1 );
int p=0 ,m =strlen(s +1 );
fo(i,1 ,m ){
int ch=s [i]-'0' ;
if (!son[p][ch])son[p][ch]=++pon;
p=son[p][ch];
}
cnt[p]++;
}
int he=0 ,ti=0 ;
fo(i,0 ,9 )if (son[0 ][i])q[++ti] =son[0 ][i];
while (he!=ti){
int p=q[++he] ;
fo(i,0 ,9 )if (son[p][i]){
int u=q[++ti] =son[p][i];
fail[u]=fail[p];
while (fail[u]&&(!son[fail[u]][i]))fail[u]=fail[fail[u]];
fail[u]=son[fail[u]][i];
cnt[u]+=cnt[fail[u]]+cnt[p];
}
}
fo(i,0 ,pon)fo(j,0 ,9 )if (!son[i][j]){
int p=fail[i];
while (p&&(!son[p][j]))
p=fail[p];
son[i][j]=son[p][j];
}
printf ("%d " ,((calc(s2)-calc(s1))%mo +mo)%mo );
return 0 ;
}