P3311 [SDOI2014]數數
阿新 • • 發佈:2018-12-21
看到匹配,自然想到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; }