BZOJ 3530 [SDOI2014]数数 (Trie图/AC自动机+数位DP)
题目大意:略
裸的AC自动机+数位DP吧...
定义f[i][x][0/1]表示已经匹配到了第i位,当前位置是x,0表示没到上限,1到上限,此时数是数量
然而会出现虚拟前导零,即前几位没有数字的情况,实际上是在0号节点原地打转,所以多加一维状态,再额外讨论第1位就行了
#include <cmath> #include <queue> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #define NN 1210 #define MM 1510 #define ll long long #define dd double #define uint unsigned int #define mod 1000000007 #define idx(X) (X-'0') #define eps (1e-9) using namespace std; int n,m,cte; int head[NN]; struct Edge{int to,nxt;}edge[NN*2]; void ae(int u,int v){ cte++;edge[cte].nxt=head[u]; head[u]=cte,edge[cte].to=v; } uint f[NN][MM][3]; int ma[NN]; namespace AC{ int ch[NN][26],fail[NN],tot,ed[NN]; void Build_Trie(char *str,int len) { int x=0; for(int i=1;i<=len;i++){ if(!ch[x][idx(str[i])]) ch[x][idx(str[i])]=++tot; x=ch[x][idx(str[i])]; }ed[x]=1; } void Build_Fail() { queue<int>q; for(int i=0;i<=9;i++) if(ch[0][i]) q.push(ch[0][i]); while(!q.empty()) { int x=q.front();q.pop(); ae(fail[x],x); for(int i=0;i<=9;i++) { if(ch[x][i]){ fail[ch[x][i]]=ch[fail[x]][i]; q.push(ch[x][i]); }else{ ch[x][i]=ch[fail[x]][i]; } } } q.push(0); while(!q.empty()) { int x=q.front();q.pop(); for(int j=head[x];j;j=edge[j].nxt){ int v=edge[j].to; ed[v]|=ed[x]; q.push(v); } } } void solve() { f[1][0][2]++; for(int j=1;j<ma[1];j++){ if(!ed[ch[0][j]]) f[1][ch[0][j]][0]++;} if(!ed[ch[0][ma[1]]]) f[1][ch[0][ma[1]]][1]++; for(int i=1;i<n;i++) { f[i+1][0][2]=1; int x=0; //nolimited for(int j=0;j<=9;j++){ if(!ed[ch[x][j]]) (f[i+1][ch[x][j]][0]+=f[i][x][0]+((j!=0)?f[i][x][2]:0))%=mod; } //limited for(int j=0;j<ma[i+1];j++) if(!ed[ch[x][j]]) (f[i+1][ch[x][j]][0]+=f[i][x][1])%=mod; if(!ed[ch[x][ma[i+1]]]) (f[i+1][ch[x][ma[i+1]]][1]+=f[i][x][1])%=mod; for(x=1;x<=tot;x++) { //nolimited for(int j=0;j<=9;j++){ if(!ed[ch[x][j]]) (f[i+1][ch[x][j]][0]+=f[i][x][0])%=mod; } //limited for(int j=0;j<ma[i+1];j++) if(!ed[ch[x][j]]) (f[i+1][ch[x][j]][0]+=f[i][x][1])%=mod; if(!ed[ch[x][ma[i+1]]]) (f[i+1][ch[x][ma[i+1]]][1]+=f[i][x][1])%=mod; //(f[i+1][ch[x][0]][2]+=f[i][x][2])%=mod; } } uint ans=0; for(int x=0;x<=tot;x++) (ans+=f[n][x][0]+f[n][x][1])%=mod; printf("%u\n",ans); } }; char str[NN]; int main() { //freopen("t1.in","r",stdin); scanf("%s",str+1); n=strlen(str+1); for(int i=1;i<=n;i++) ma[i]=idx(str[i]); scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%s",str+1); int len=strlen(str+1); AC::Build_Trie(str,len); }AC::Build_Fail(); AC::solve(); return 0; }