求 [1,n](n≤101000) 中不包含给定数字作为字串的数字个数 (mod109+7) ,给定数字总长度 ≤1500 。
一眼看过去是一个用AC自动机表示状态,用数位dp的模板题
注意前导零是不会被统计到的
具体见代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1600,maxLen = 10;
const int mod = 1e9+7;
#define LL long long
queue<int> Q;
int toid(char c){ return c - '0'; }
struct acam{
int nex[maxn][maxLen],fail[maxn];
int cnt[maxn];
int _cnt,root;
int newNode(){
memset(nex[_cnt],fail[_cnt] = -1,sizeof(nex[_cnt]));
cnt[_cnt] = 0;
return _cnt++;
}
void init(){
_cnt = 0;
root = newNode();
}
void insert(char *arr){
int st = root;
for(int i=0;arr[i];i++){
int & stx = nex[st][toid(arr[i])];
if(stx == -1) stx = newNode();
st = stx;
}
cnt[st]++;
}
void build(){
while(Q.empty()==false) Q.pop();
fail[root] = root;
int st;
for(int i=0;i<maxLen;i++){
if((st = nex[root][i]) != -1){
fail[st] = root;
Q.push(st);
}
else nex[root][i] = root;
}
while(Q.empty()==false){
st = Q.front(),Q.pop();
for(int i=0;i<maxLen;i++){
if(nex[st][i] != -1){
int fst = fail[st],son = nex[st][i];
while(fst != root && nex[fst][i] == -1)
fst = fail[fst];
fail[son] = nex[fst][i] == -1 ? root : nex[fst][i];
Q.push(son);
}
else{
nex[st][i] = nex[fail[st]][i];
}
}
}
}
}acam;
int num[maxn];
LL dp[maxn][2][maxn][2];
LL dfs(int pos,bool bnd,int st,int az){
if(pos < 0) return 1;
LL & ndp = dp[pos][bnd][st][az];
if(~ndp) return ndp;
ndp = 0;
int bound = bnd ? num[pos] : 9;
for(int i=0;i<=bound;i++){
if(az && i == 0){
(ndp += dfs(pos-1,bnd && i == bound,st,az && i == 0))%= mod;
}
else{
int nex = acam.nex[st][i];
if(acam.cnt[nex] == 0)
(ndp += dfs(pos-1,bnd && i == bound,nex,az && i == 0)) %= mod;
}
}
return ndp;
}
char arr[2000];
int main(){
scanf("%s",arr);
int len = strlen(arr);
reverse(arr,arr+len);
for(int i=0;i<len;i++) num[i] = toid(arr[i]);
int m;
scanf("%d",&m);
acam.init();
while(m--){
scanf("%s",arr);
acam.insert(arr);
}
acam.build();
memset(dp,-1,sizeof(dp));
printf("%lld\n",(dfs(len-1,true,0,true)-1+mod) % mod);
return 0;
}