题目大意
求不大于N的正整数中,看作字符串(不包含前缀
题目分析
不大于某个数,然后对于数字的某些位有特殊要求,这是经典的数位dp模型。
那如何解决子串的约束条件呢?可以发现约束条件相当于多串匹配。那我们考虑就S集合建立
在建立自动机,处理fail数组时,我们同时处理布尔数组markx,表示节点x及其
我们从高位往低位(字符串前往后)枚举,设fi,j,0..1表示枚举到第i位,当前状态在自动机内的
我们枚举
注意不能有前导0,但是仍需考虑不足数位的情况。所以我们还可以在每次
设
时间复杂度即为O(n×tot)。
代码实现
作者闲得蛋疼,开了滚动数组,空间大跳楼。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int P=1000000007;
const int N=1200;
const int L=1500;
int f[2][L+1][2];
queue<int> Q;
char n[N+1];
int d,ans,m;
const int W=10;
char str[L+1];
struct AC_automation
{
int fail[L+1],next[L+1][W];
bool mark[L+1];
int tot,root;
int newnode()
{
fail[tot]=-1;
for (int i=0;i<W;i++)
next[tot][i]=-1;
mark[tot]=false;
return tot++;
}
void init()
{
tot=0;
root=newnode();
}
void insert()
{
int l=strlen(str),rt=root;
for (int i=0;i<l;i++)
if (next[rt][str[i]-'0']!=-1)
rt=next[rt][str[i]-'0'];
else
{
next[rt][str[i]-'0']=newnode();
rt=next[rt][str[i]-'0'];
}
mark[rt]=true;
}
void build()
{
for (int i=0;i<W;i++)
if (next[root][i]==-1)
next[root][i]=root;
else
{
fail[next[root][i]]=root;
Q.push(next[root][i]);
}
while (!Q.empty())
{
int rt=Q.front();
Q.pop();
mark[rt]|=mark[fail[rt]];
for (int i=0;i<W;i++)
if (next[rt][i]==-1)
next[rt][i]=next[fail[rt]][i];
else
{
fail[next[rt][i]]=next[fail[rt]][i];
Q.push(next[rt][i]);
}
}
}
void dp()
{
int now=0,tsf=1;
for (int i=1;i<n[0]-'0';i++)
f[tsf][next[root][i]][0]++;
f[tsf][next[root][n[0]-'0']][1]++;
for (int i=0;i<d-1;i++)
{
now^=1,tsf^=1;
memset(f[tsf],0,sizeof f[tsf]);
for (int j=1;j<W;j++)
f[tsf][next[root][j]][0]++;
for (int j=0;j<tot;j++)
if (!mark[j])
{
(f[tsf][next[j][n[i+1]-'0']][1]+=f[now][j][1])%=P;
for (int k=0;k<n[i+1]-'0';k++)
(f[tsf][next[j][k]][0]+=f[now][j][1])%=P;
for (int k=0;k<W;k++)
(f[tsf][next[j][k]][0]+=f[now][j][0])%=P;
}
}
ans=0;
for (int i=0;i<tot;i++)
if (!mark[i])
(((ans+=f[tsf][i][0])%=P)+=f[tsf][i][1])%=P;
}
}atm;
int main()
{
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%s",n);
d=strlen(n);
atm.init();
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
scanf("%s",str);
atm.insert();
}
atm.build();
atm.dp();
printf("%d\n",ans);
fclose(stdin);
fclose(stdout);
}