bzoj3530 [Sdoi2014]数数

Description

我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串。例如当S=(22,333,0233)时,233是幸运数,2333、20233、3223不是幸运数。
    给定N和S,计算不大于N的幸运数个数。

Input

    输入的第一行包含整数N。
    接下来一行一个整数M,表示S中元素的数量。
    接下来M行,每行一个数字串,表示S中的一个元素。

Output

    输出一行一个整数,表示答案模109+7的值。

Sample Input

20
3
2
3
14

Sample Output

14

HINT

 下表中l表示N的长度,L表示S中所有串长度之和。

1 < =l < =1200 , 1 < =M < =100 ,1 < =L < =1500

 

正解:$AC$自动机+数位$dp$。

很裸的题,直接在$AC$自动机上跑数位$dp$就行了。

细节:$AC$自动机建成$trie$图可以保证复杂度。

第一位不能为$0$,且只有位数为$n$时才会有限制。

 

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 #define rhl (1000000007)
 6 
 7 using namespace std;
 8 
 9 int f[1505][1205][2],ch[1505][26],val[1505],fa[1505],q[1505],n,m,sz,len,ans;
10 char s[1505],cs[1505];
11 
12 il int gi(){
13   RG int x=0,q=1; RG char ch=getchar();
14   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
15   if (ch=='-') q=-1,ch=getchar();
16   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
17   return q*x;
18 }
19 
20 il void insert(char *s,RG int len){
21   RG int x=0,c;
22   for (RG int i=1;i<=len;++i){
23     c=s[i]-'0';
24     if (!ch[x][c]) ch[x][c]=++sz; x=ch[x][c];
25   }
26   val[x]=1; return;
27 }
28 
29 il void build(){
30   RG int h=0,t=0;
31   for (RG int c=0;c<10;++c) if (ch[0][c]) q[++t]=ch[0][c];
32   while (h<t){
33     RG int x=q[++h],v,j;
34     for (RG int c=0;c<10;++c){
35       if (!ch[x][c]){ ch[x][c]=ch[fa[x]][c]; continue; }
36       v=ch[x][c],j=fa[x]; while (j && !ch[j][c]) j=fa[j];
37       fa[v]=ch[j][c],q[++t]=v,val[v]|=val[fa[v]];
38     }
39   }
40   return;
41 }
42 
43 il int dfs(RG int x,RG int p,RG int l){
44   if (p>n) return 1;
45   if (f[x][p][l]!=-1) return f[x][p][l];
46   RG int res=0,lim=s[p]-'0';
47   for (RG int c=0;c<10;++c){
48     if (l && c>lim) break;
49     if (val[ch[x][c]]) continue;
50     res+=dfs(ch[x][c],p+1,l&&c==lim);
51     if (res>=rhl) res-=rhl;
52   }
53   return f[x][p][l]=res;
54 }
55 
56 int main(){
57 #ifndef ONLINE_JUDGE
58   freopen("number.in","r",stdin);
59   freopen("number.out","w",stdout);
60 #endif
61   scanf("%s",s+1),n=strlen(s+1),m=gi();
62   for (RG int i=1;i<=m;++i)
63     scanf("%s",cs+1),len=strlen(cs+1),insert(cs,len);
64   build(),memset(f,-1,sizeof(f));
65   for (RG int i=1;i<=n;++i)
66     for (RG int j=1;j<10;++j){
67       if (i==1 && j>s[i]-'0') break;
68       if (val[ch[0][j]]) continue;
69       ans+=dfs(ch[0][j],i+1,i==1&&j==s[i]-'0');
70       if (ans>=rhl) ans-=rhl;
71     }
72   cout<<ans; return 0;
73 }

 

posted @ 2018-02-27 08:49  wfj_2048  阅读(154)  评论(0编辑  收藏  举报