【Luogu】P3311数数(AC自动机上DP)
蒟蒻今天终于学会了AC自动机,感觉很稳
(后一句愚人节快乐)
这题开一个f[i][j][k]表示有没有受到限制,正在枚举第j位,来到了AC自动机的第k个节点
的方案数
随后可以刷表更新
注意如果是在枚举第一位的话注意前导0
#include<cstdio> #include<algorithm> #include<cstring> #include<cctype> #include<cstdlib> #include<queue> #define maxl 2000 #define maxu 10 #define mod 1000000007 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } inline int count(int i){ return i-'0'; } int tree[maxl*maxu][maxu]; int fail[maxl*maxu]; int val[maxl*maxu]; int tot; char c[maxl]; char s[maxl]; long long f[3][maxl][maxl]; bool vis[maxl]; void update(){ int n=strlen(c+1); int now=0; for(int i=1;i<=n;++i){ if(tree[now][count(c[i])]==0) tree[now][count(c[i])]=++tot; now=tree[now][count(c[i])]; } val[now]++; return; } void makefail(){ queue<int>q; for(int i=0;i<10;++i) if(tree[0][i]) q.push(tree[0][i]); while(!q.empty()){ int from=q.front();q.pop(); for(int i=0;i<10;++i){ if(tree[from][i]==0){ tree[from][i]=tree[fail[from]][i]; continue; } fail[tree[from][i]]=tree[fail[from]][i]; val[tree[from][i]]|=val[tree[fail[from]][i]]; q.push(tree[from][i]); } } return; } inline void add(long long &a,int b){ a=(a+b)%mod; } int main(){ scanf("%s",s+1);int n=strlen(s+1); int m=read(); for(int i=1;i<=m;++i){ scanf("%s",c+1); update(); } long long ans=0; makefail(); for(int i=0;i<n;++i) for(int j=0;j<=tot;++j){ if(f[0][i][j]){ int now=s[i+1]-'0'; for(int k=0;k<now;++k){ int nxt=tree[j][k]; if(val[nxt]==0) add(f[1][i+1][nxt],f[0][i][j]); } int nxt=tree[j][now]; if(val[nxt]==0) add(f[0][i+1][nxt],f[0][i][j]); } if(f[1][i][j]){ for(int k=0;k<10;++k){ int nxt=tree[j][k]; if(val[nxt]==0) add(f[1][i+1][nxt],f[1][i][j]); } } if(j==0){ if(i==0){ int now=s[i+1]-'0'; for(int k=1;k<now;++k){ int nxt=tree[j][k]; if(val[nxt]==0) add(f[1][i+1][nxt],1); } int nxt=tree[j][now]; if(val[nxt]==0) add(f[0][i+1][nxt],1); } else{ for(int k=1;k<10;++k){ int nxt=tree[j][k]; if(val[nxt]==0) add(f[1][i+1][nxt],1); } } } } for(int i=0;i<=tot;++i){ add(ans,f[0][n][i]); add(ans,f[1][n][i]); } ans=(ans+mod)%mod; printf("%lld\n",ans); }