【JZOJ5332】【NOIP2017提高A组模拟8.23】密码

Description

这里写图片描述

Data Constraint

这里写图片描述

Solution

考场上没想到挺可惜的,明明以前做过两次的~
我们将正整数放到一个AC自动机上跑。做一个数位dp,设f[i][j][k][0..1]表示当前到第i位,在自动机上节点j包含k个秘钥,前i位是否与上界相同的方案。我们每次枚举下一位放的数字,看一下AC自动机会跳至哪里转移一下。复杂度O(S*s*k*10)。

Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll maxn=505,mo=1e9+7;
ll f[maxn][10],g[maxn][205][11][2],d[maxn],fa[maxn],v[maxn],a[maxn],mi[maxn],b[maxn];
ll n,m,i,t,j,k,l,x,y,z,num,ans;
char s[maxn],s1[maxn],s2[maxn];
void bfs(){
    int i=0,j=1,x,k;
    while (i<j){
        x=v[++i];
        for (k=0;k<10;k++){
            if (!f[x][k]) continue;
            y=fa[x];
            while (!f[y][k] && y) y=fa[y];
            v[++j]=f[x][k];if (f[y][k]!=f[x][k])fa[v[j]]=f[y][k];
            d[v[j]]+=d[fa[v[j]]];
        }
    }
}
ll dg(){
    memset(g,0,sizeof(g));
    ll i,j,k,l,x,y=0;b[a[0]+1]=1;
    for (i=a[0];i>=1;i--)
        b[i]=(b[i+1]+mi[a[0]-i]*a[i]%mo)%mo;
    g[0][0][0][1]=1;
    for (i=0;i<=a[0];i++)
        for (j=0;j<=num;j++){
            for (k=0;k<m;k++){
                if (i==a[0]) break;
                if (g[i][j][k][0]){
                    for (l=0;l<=9;l++){x=j;
                        while (!f[x][l] && x) x=fa[x];
                        if (f[x][l]) x=f[x][l];
                        g[i+1][x][min(m,k+d[x])][0]=(g[i][j][k][0]+g[i+1][x][min(m,k+d[x])][0])%mo;
                    }
                }
                if (g[i][j][k][1]){
                    for (l=0;l<a[i+1];l++){x=j;
                        while (!f[x][l] && x) x=fa[x];
                        if (f[x][l]) x=f[x][l];
                        g[i+1][x][min(m,k+d[x])][0]=(g[i][j][k][1]+g[i+1][x][min(m,k+d[x])][0])%mo;
                    }
                    x=j;
                    while (!f[x][l] && x) x=fa[x];
                    if (f[x][l]) x=f[x][l];
                    g[i+1][x][min(m,k+d[x])][1]=(g[i][j][k][1]+g[i+1][x][min(m,k+d[x])][1])%mo;
                }
            }
            y=(y+g[i][j][m][0]*mi[a[0]-i]%mo)%mo;
            y=(y+g[i][j][m][1]*b[i+1]%mo)%mo;
        }
    return y;
}
int main(){
    freopen("word.in","r",stdin);freopen("word.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    scanf("%s%s\n",s+1,s1+1);t=strlen(s+1);mi[0]=1;
    for (i=1;i<=500;i++)mi[i]=mi[i-1]*10%mo;
    for (i=1;i<=t;i++)a[i]=s[i]-48;a[0]=t;
    for (i=1;i<=n;i++){
        x=0;
        scanf("%s\n",s2+1);t=strlen(s2+1);
        for (j=1;j<=t;j++){
            if (!f[x][s2[j]-48]) f[x][s2[j]-48]=++num;
            x=f[x][s2[j]-48];
        }
        d[x]++;
    }
    bfs();
    ans=-dg();t=strlen(s1+1);
    for (i=1;i<=t;i++)a[i]=s1[i]-48;a[0]=t;
    ans=(ans+dg()+mo)%mo;
    printf("%lld\n",ans);
}
发布了257 篇原创文章 · 获赞 451 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/crybymyself/article/details/77513002
今日推荐