题目链接
如果子串必须是
S
S
S的前缀,那么是一个经典的单个字符串匹配问题,用KMP+数位DP记录目前匹配到的位置即可。
而任意子串就相当于
S
S
S的所有后缀的前缀,是多个字符串匹配问题,又注意到有用的只有每个后缀的前
d
/
2
d/2
d/2个字符,对它们建立
A
C
AC
AC自动机即可,效率
O
(
10
d
2
s
)
O(10d^{2}s)
O(10d2s)。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll P=1e9+7;
const int N=55,M=50005,K=10;
char ch[M];
void read(int* a,int& n){
scanf("%s",ch+1); n=strlen(ch+1);
for(int i=1;i<=n;i++) a[i]=ch[i]-'0';
}
int n,m,a[M],to[M][K],fa[M],ct=1;
bool is[M];
void add(int l,int r){
int u=1;
for(int i=l;i<=r;i++){
int x=a[i];
if(!to[u][x]) to[u][x]=++ct;
u=to[u][x];
}
is[u]=1;
}
void bfs(){
queue<int>q; fa[1]=1;
for(int i=0;i<K;i++){
int& u=to[1][i];
if(u) fa[u]=1,q.push(u);
else u=1;
}
while(!q.empty()){
int u=q.front(); q.pop();
for(int i=0;i<K;i++){
int& v=to[u][i];
if(v) fa[v]=to[fa[u]][i],q.push(v);
else v=to[fa[u]][i];
}
}
}
ll f[N][M];
ll cnt(int* s){
memset(f,0,sizeof(f));
int u=1;
for(int i=0;i<m;i++){
for(int k=0;k<s[i+1];k++){
int v=to[u][k]; if(is[v]) v=0;
(f[i+1][v]+=1)%=P;
}
for(int j=0;j<=ct;j++){
for(int k=0;k<K;k++) if(f[i][j]){
int v=to[j][k]; if(is[v]) v=0;
(f[i+1][v]+=f[i][j])%=P;
}
}
u=to[u][s[i+1]]; if(is[u]) u=0;
}
//cout<<(f[m][0]+(u==0))%P<<endl;
return (f[m][0]+(u==0))%P;
}
int x[N],y[N];
int main()
{
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
read(a,n),read(x,m),read(y,m);
for(int i=m;i;i--){
if(!x[i]) x[i]=9;
else{
x[i]--; break;
}
}
for(int i=1;i+m/2-1<=n;i++) add(i,i+m/2-1);
bfs(); //return 0;
/*for(int i=1;i<=ct;i++){
cout<<"u="<<i<<" fa="<<fa[i]<<endl;
for(int j=0;j<K;j++) cout<<to[i][j]<<" ";
puts("");
}*/
cout<<(cnt(y)+P-cnt(x))%P<<endl;
return 0;
}