1. 程式人生 > >P3311 [SDOI2014]數數

P3311 [SDOI2014]數數

P3311 [SDOI2014]數數

看到匹配,自然想到AC自動機

控制位數的當然容易做,\(emmm\) 這裡是要求小於\(n\),後面不會了怎麼辦

好像和數位dp有點關係,首先\(dp1_{i,j}\)跑一邊,小於\(strlen(n)\)長度的個數

重點來了,\(dp2_{i,j,1/0}\) 第三維表示是否達到上界

#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
typedef long long LL;
const LL maxn=2000000;
const LL MOD=1e9+7;
LL n,ans,nod,m;
LL son[maxn][20],val[maxn],dp1[6000][6000],dp2[6000][6000][2],fail[maxn];
char book[maxn],s[maxn];
inline void Build(char *s){
    LL len=strlen(s),u=0;
    for(LL i=0;i<len;++i){
        LL c=s[i]-'0';
        if(!son[u][c])
            son[u][c]=++nod;
        u=son[u][c];
    }
    val[u]|=1;
}
inline void Bfail(){
    queue<LL> que;
    for(LL i=0;i<10;++i)
        if(son[0][i])
            que.push(son[0][i]);
    while(que.size()){
        LL u=que.front(); que.pop();
        for(LL i=0;i<10;++i){
            LL v=son[u][i];
            if(v)
                fail[v]=son[fail[u]][i],
                val[v]|=val[fail[v]],
                que.push(v);
            else 
                son[u][i]=son[fail[u]][i];
        }
    }
}
inline void Solve(){
    dp1[0][0]=1;
    for(LL i=0;i<n;++i){
        for(LL u=0;u<=nod;++u){
            if(val[u])
                continue;
            for(LL k=0;k<10;++k){
                LL v=son[u][k];
                if(val[v])
                    continue;
                if(!i&&!k)
                    continue;
                dp1[i+1][v]=(dp1[i+1][v]+dp1[i][u])%MOD;
            }
        }
    }
    for(LL i=1;i<n;++i)
        for(LL u=0;u<=nod;++u)
            ans=(ans+dp1[i][u])%MOD;
    dp2[0][0][1]=1;
    for(LL i=0;i<n;++i){
        for(LL u=0;u<=nod;++u){
            if(val[u])
                continue;
            for(LL k=0;k<10;++k){
                LL v=son[u][k];
                if(val[v])
                    continue;
                if(!i&&!k)
                    continue;
                dp2[i+1][v][0]=(dp2[i+1][v][0]+dp2[i][u][0])%MOD;
                if(book[i]-'0'>k)
                    dp2[i+1][v][0]=(dp2[i+1][v][0]+dp2[i][u][1])%MOD;
                if(book[i]-'0'==k)
                    dp2[i+1][v][1]=(dp2[i+1][v][1]+dp2[i][u][1])%MOD;
            }
        }
    }
    for(LL u=0;u<=nod;++u)
        ans=(ans+dp2[n][u][0])%MOD,
        ans=(ans+dp2[n][u][1])%MOD;
}
int main(){
    scanf(" %s",book);
    n=strlen(book);
    scanf("%lld",&m);
    for(LL i=1;i<=m;++i)
        scanf(" %s",s),
        Build(s);
    Bfail();
    Solve();
    printf("%lld",ans);
    return 0;
}