正解:AC自动机+dp
解题报告:
传送门!
首先看到多串匹配balabala显然想到建个AC自动机?
然后可以用一点儿数位dp的思想地想下(,,,其实并不算QAQ
幸运数可以分为两类:位数<n的和位数=n的
下面分别考虑下
对位数<n的,相当于就没有任何约束,直接dp转移下就好
然后对位数=n的,另外做一次dp,然后多设一组状态表示当前是否相等(就和数位dp差不多的那种,,,
最后加起来就欧克!
啊说得好潦草,,,算了反正就大概这个意思,看下代码趴QwQ
![](https://i-blog.csdnimg.cn/blog_migrate/a2b7024cb6a8cccd23244148c90016f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/aa7790439652fcf252898472b6dc57b7.gif)
#include<bits/stdc++.h> using namespace std; #define il inline #define gc getchar() #define ll long long #define int long long #define ri register int #define rb register bool #define rc register char #define rp(i,x,y) for(ri i=x;i<=y;++i) #define my(i,x,y) for(ri i=x;i>=y;--i) const int N=1500+100,mod=1e9+7; int m,nod_cnt,lth,g[N][N],f[N][N][2]; ll as; struct nod{int to[10],fail;bool flg;}tr[N]; char str[N],n[N]; queue<int>Q; il int read() { rc ch=gc;ri x=0;rb y=1; while(ch!='-' && (ch>'9' || ch<'0'))ch=gc; if(ch=='-')ch=gc,y=0; while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc; return y?x:x; } il void insert(char *s) { ri lth=strlen(s+1),nw=0; rp(i,1,lth) { if(!tr[nw].to[s[i]^'0'])tr[nw].to[s[i]^'0']=++nod_cnt; nw=tr[nw].to[s[i]^'0']; } tr[nw].flg=1; } il void bfs() { rp(i,0,9)if(tr[0].to[i])Q.push(tr[0].to[i]); while(!Q.empty()) { ri nw=Q.front();Q.pop();tr[nw].flg|=tr[tr[nw].fail].flg; rp(i,0,9) if(tr[nw].to[i])Q.push(tr[nw].to[i]),tr[tr[nw].to[i]].fail=tr[tr[nw].fail].to[i]; else tr[nw].to[i]=tr[tr[nw].fail].to[i]; } } main() { // freopen("3311.in","r",stdin);freopen("3311.out","w",stdout); scanf("%s",n+1);lth=strlen(n+1); m=read();while(m--){scanf("%s",str+1);insert(str);}bfs(); g[0][0]=f[0][0][1]=1; rp(i,0,lth-2) { rp(j,0,nod_cnt) if(!tr[j].flg) rp(k,0,9) if(!tr[tr[j].to[k]].flg) { if(!i && !k)continue; g[i+1][tr[j].to[k]]=(g[i+1][tr[j].to[k]]+g[i][j])%mod; } } rp(i,1,lth-1)rp(j,0,nod_cnt)as=(as+g[i][j])%mod; rp(i,0,lth-1) { rp(j,0,nod_cnt) { if(!tr[j].flg) rp(k,0,9) if(!tr[tr[j].to[k]].flg) { if(!i && !k)continue; f[i+1][tr[j].to[k]][0]=(f[i+1][tr[j].to[k]][0]+f[i][j][0])%mod; if(k<(n[i+1]^'0'))f[i+1][tr[j].to[k]][0]=(f[i+1][tr[j].to[k]][0]+f[i][j][1])%mod; if(k==(n[i+1]^'0'))f[i+1][tr[j].to[k]][1]=(f[i+1][tr[j].to[k]][1]+f[i][j][1])%mod; } } } rp(i,0,nod_cnt)as=(as+f[lth][i][1])%mod,as=(as+f[lth][i][0])%mod; printf("%lld\n",as); return 0; }
最后说下这题的代码实现的时候的小细节,,,
其实都挺普通的只是我没注意到所以给自己强调下QAQ
第一个是在bfs做fail的时候有一句"tr[nw].flg|=tr[tr[nw].fail].flg;"
虽然数据太水不加也能A但不加显然是WA的,,,
放个hack数据趴,1234 2 121 2,如果不加的答案是930,正解是890
第二个是在位数=n的位数的时候,判相等记得是"(n[i+1]^'0'",就,记得+1这个操作鸭,,,
没辣!overr!
tr[nw].flg|=tr[tr[nw].fail].flg;