【jzoj5332】【NOIP2017提高A組模擬8.23】【密碼】【ac自動機】【動態規劃】

description

這裏寫圖片描述

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章