构建幸运数的AC自动机。令dp[i][j][k]表示匹配到n的第i位,在AC自动机的第j位,状态为k的方案。其中状态定义如下:
k=0表示前i为比n的前i位小;k=1为相等;k=2为大于。
然后对每一个i统计答案即可。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define mod 1000000007
using namespace std;
int n,m,h[1505],dp[1205][1505][3],a[1205];
void up(int &x,int y){
x+=y; if (x>=mod) x-=mod;
}
struct acam_node{
int tot,ch[1505][10],fa[1505]; bool bo[1505];
void ins(){
int now=0,k; char c=getchar();
while (c<'0' || c>'9') c=getchar();
for (; c>='0' && c<='9'; c=getchar()){
k=c-'0';
if (!ch[now][k]) ch[now][k]=++tot;
now=ch[now][k];
}
bo[now]=1;
}
void build(){
int head=0,tail=0,i;
for (i=0; i<10; i++) if (ch[0][i]) h[++tail]=ch[0][i];
while (head<tail){
int x=h[++head],y;
for (i=0; i<10; i++) if (y=ch[x][i]){
h[++tail]=y; fa[y]=ch[fa[x]][i];
bo[y]|=bo[fa[y]];
} else ch[x][i]=ch[fa[x]][i];
}
}
void solve(){
int ans=0,i,j,k,t;
for (i=1; i<=9; i++){
k=ch[0][i]; if (bo[k]) continue;
if (i<a[1]) dp[1][k][0]++; else
if (i==a[1]) dp[1][k][1]++; else dp[1][k][2]++;
}
for (i=0; i<=tot; i++){
up(ans,dp[1][i][0]); up(ans,dp[1][i][1]);
if (n>1) up(ans,dp[1][i][2]);
}
for (i=1; i<n; i++){
for (j=0; j<=tot; j++) if (dp[i][j][0] || dp[i][j][1] || dp[i][j][2])
for (k=0; k<10; k++){
t=ch[j][k]; if (bo[t]) continue;
up(dp[i+1][t][0],dp[i][j][0]); up(dp[i+1][t][2],dp[i][j][2]);
if (k<a[i+1]) up(dp[i+1][t][0],dp[i][j][1]);
else if (k==a[i+1]) up(dp[i+1][t][1],dp[i][j][1]);
else up(dp[i+1][t][2],dp[i][j][1]);
}
for (k=0; k<=tot; k++){
up(ans,dp[i+1][k][0]); up(ans,dp[i+1][k][1]);
if (i+1<n) up(ans,dp[i+1][k][2]);
}
}
printf("%d\n",ans);
}
}acam;
int main(){
char c=getchar(); while (c<'0' || c>'9') c=getchar();
for (n=0; c>='0' && c<='9'; c=getchar()) a[++n]=c-'0';
scanf("%d",&m);
while (m--) acam.ins();
acam.build(); acam.solve();
return 0;
}
by lych
2016.4.4