BZOJ3530[Sdoi2014]数数——AC自动机+DP

题目描述

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

输入

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

输出

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

样例输入

20
3
2
3
14

样例输出

14

提示

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

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

这道题和bzoj1030比较像,建议先做一下那道题。虽然是一道AC自动机的题但重点是dp,因为不只有位数限制,每一位还有限制数值,所以不能只用f[i][j]表示第i位走到了j节点。因为有限制值所以我们不妨在前面再加一维变成f[k][i][j](k=0或k=1),f[0][i][j]表示第i为走到j节点需要受限制(即前几位都等于每一位限制值),f1[1][i][j]则表示第i位走到j节点不受限制(即前几位有至少一位低于限制值)。当枚举f[0][i][j]时如果j节点所代表的数字小于第i位的限制值,那就可以转移到f[1][i+1][x](x为j的子节点).对于f[0][i][j],因为这一位受限制,所以下一位也要相应受限制,即f[0][i][j]转移到f[0][i+1][x].对于f[1][i][j],因为这一位不受限制,下一位一定不受限制,所以从f[1][i][j]转移到f[1][i][x]。

最后附上代码。

  1 #include<cmath>
  2 #include<queue>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<cstdlib>
  6 #include<iostream>
  7 #include<algorithm>
  8 using namespace std;
  9 struct tree
 10 {
 11     int fail;
 12     int vis[11];
 13     int end;
 14 }a[1600];
 15 char s[1600];
 16 char t[1250];
 17 int cnt;
 18 int n;
 19 int m;
 20 long long ans;
 21 long long f[3][1250][1600];
 22 int mod=1e9+7;
 23 void build(char *s)
 24 {
 25     int l=strlen(s);
 26     int now=0;
 27     for(int i=0;i<l;i++)
 28     {
 29         int x=s[i]-'0';
 30         if(!a[now].vis[x])
 31         {
 32             a[now].vis[x]=++cnt;
 33         }
 34         now=a[now].vis[x];
 35     }
 36     a[now].end++;
 37 }
 38 void getfail()
 39 {
 40     queue<int>q;
 41     for(int i=0;i<10;i++)
 42     {
 43         if(a[0].vis[i]!=0)
 44         {
 45             a[a[0].vis[i]].fail=0;
 46             q.push(a[0].vis[i]);
 47         }
 48     }
 49     while(!q.empty())
 50     {
 51         int now=q.front();
 52         q.pop();
 53         for(int i=0;i<10;i++)
 54         {
 55             if(!a[now].vis[i])
 56             {
 57                 a[now].vis[i]=a[a[now].fail].vis[i];
 58                 continue;
 59             }
 60             a[a[now].vis[i]].fail=a[a[now].fail].vis[i];
 61             a[a[now].vis[i]].end|=a[a[a[now].fail].vis[i]].end;
 62             q.push(a[now].vis[i]);
 63         }
 64     }
 65 }
 66 int main()
 67 {
 68     scanf("%s",t+1);
 69     m=strlen(t+1);
 70     scanf("%d",&n);
 71     for(int i=1;i<=n;i++)
 72     {
 73         scanf("%s",s);
 74         build(s);
 75     }
 76     getfail();
 77     for(int i=0;i<m;i++)
 78     {
 79         for(int j=0;j<=cnt;j++)
 80         {
 81             if(!j)
 82             {
 83                 if(!i)
 84                 {
 85                     int x=t[i+1]-'0';
 86                     for(int k=1;k<x;k++)
 87                     {
 88                         if(!a[a[j].vis[k]].end)
 89                         {
 90                             f[1][i+1][a[j].vis[k]]+=1;
 91                             f[1][i+1][a[j].vis[k]]%=mod;
 92                         }
 93                     }
 94                     if(!a[a[j].vis[x]].end)
 95                     {
 96                         f[0][i+1][a[j].vis[x]]+=1;
 97                         f[0][i+1][a[j].vis[x]]%=mod;
 98                     }
 99                 }
100                 else
101                 {
102                     for(int k=1;k<=9;k++)
103                     {
104                         if(!a[a[j].vis[k]].end)
105                         {
106                             f[1][i+1][a[j].vis[k]]+=1;
107                             f[1][i+1][a[j].vis[k]]%=mod;
108                         }
109                     }
110                 }
111             }
112             if(f[0][i][j])
113             {
114                 int x=t[i+1]-'0';
115                 for(int k=0;k<x;k++)
116                 {
117                     if(!a[a[j].vis[k]].end)
118                     {
119                         f[1][i+1][a[j].vis[k]]+=f[0][i][j];
120                         f[1][i+1][a[j].vis[k]]%=mod;
121                     }
122                 }
123                 if(!a[a[j].vis[x]].end)
124                 {
125                     f[0][i+1][a[j].vis[x]]+=f[0][i][j];
126                     f[0][i+1][a[j].vis[x]]%=mod;
127                 }
128             }
129             if(f[1][i][j])
130             {
131                 for(int k=0;k<=9;k++)
132                 {
133                     if(!a[a[j].vis[k]].end)
134                     {
135                         f[1][i+1][a[j].vis[k]]+=f[1][i][j];
136                         f[1][i+1][a[j].vis[k]]%=mod;
137                     }
138                 }
139             }
140         }
141     }
142     for(int i=0;i<=cnt;i++)
143     {
144         ans+=f[0][m][i];
145         ans%=mod;
146         ans+=f[1][m][i];
147         ans%=mod;
148     }
149     printf("%lld",ans);
150 }
View Code

猜你喜欢

转载自www.cnblogs.com/Khada-Jhin/p/9171622.html