【jzoj5332】【NOIP2017提高A组模拟8.23】【密码】【ac自动机】【动态规划】

时间:2022-12-17 14:22:34

description

【jzoj5332】【NOIP2017提高A组模拟8.23】【密码】【ac自动机】【动态规划】

solution

先把秘钥建ac自动机,设f[i][j][k][l]表示现在填到第i位,对应ac自动机上j结点,包含k个秘钥,有没有顶上界,枚举下一个填什么转移即可。

code

#include<set>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define fr(i,j) for(int i=begin[j];i;i=next[i])
using namespace std;
int const mn=2*1e5+9,ml=500+9,mo=1e9+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;
}