分析
我们把数字考虑为字符串,那么现在我们就是要求出有多少方案满足 没有出现在
串中。
关于这道题,因为我们要对子串考虑,比较自然考虑到
树和
。由于
并不能很好处理失配的问题,那么考虑
自动机。我们定义
其中
表示,该节点为一个
的结尾,那么当我们转移到这个点的时候是非法的。但是在
自动机上不知每个串的插入的地方是非法的,如果串
是
的子串,而且
,那么
。而
指针指向的就是一个串的最长后缀,所以我们才考虑到
。
那么现在我们处理了子串的合法性,定义
为已经考虑长度为
,当前节点为
的合法答案,那么
,现在考虑我们构成的串
在数值上要小于等于
。那么这个可以很好的数位
。从而限制我们转移。细节还是见代码,要注意没有前导零的时候不能转移到
上的其他节点,因为这个时候我们的串还没开始。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1600,mod = 1e9 + 7;
int f[1300][N][2][2],fail[N],ch[N][10],val[N],size;
int n;
char m[1300];
void insert(char *S) {
int len = strlen(S + 1),u = 0;
for(int i = 1;i <= len;i++) {
int c = (S[i] - '0');
if(!ch[u][c]) ch[u][c] = ++size;
u = ch[u][c];
}val[u] |= 1;
}
void build() {
queue<int> Q;
for(int i = 0;i < 10;i++) if(ch[0][i]) Q.push(ch[0][i]);
while(!Q.empty()) {
int x = Q.front();Q.pop();
for(int i = 0;i < 10;i++) {
int y = ch[x][i];
if(y) {fail[ch[x][i]] = ch[fail[x]][i];val[y] |= val[fail[y]];Q.push(y);}
else ch[x][i] = ch[fail[x]][i];
}
}
}
void inc(int &x,int y) {x = (x + y) % mod;}
int dfs(int now,int pos,int limit,int st) {
if(now <= 0) return !val[pos];
if(val[pos]) return 0;
if(f[now][pos][limit][st] != -1) return f[now][pos][limit][st];
int x = limit ? (m[now] - '0') : 9,res = 0;
for(int i = 0;i <= x;i++) {
inc(res, dfs(now - 1,(st && (i == 0)) ? 0 : ch[pos][i],(limit && (i + '0' == m[now])),(st && (i == 0))) );
}
return f[now][pos][limit][st] = res;
}
int main() {
scanf("%s%d",m + 1,&n);
int len = strlen(m + 1);
for(int i = 1;i <= n;i++) {
static char S[N];scanf("%s",S + 1);insert(S);
}
build();reverse(m + 1,m + 1 + len);
memset(f,-1,sizeof(f));
int ans = dfs(len,0,1,1);inc(ans,mod - 1);
cout << ans << endl;return 0;
}
京公网安备 11010502036488号