CF585F Digits of Number Pi
Link
Solution
一个小 trick ,只需要判断是否出现过任何长度为 \(\lfloor \frac{d}{2} \rfloor\) 即可,长度大于这个的可以不管,因为短串一定是长串的子串,后者约束条件反而更强,满足前者一定满足后者。
那么就将 \(s\) 中长为 \(\lfloor \frac{d}{2} \rfloor\) 的所有子串插入到 AC 自动机里,统计个数就直接在 AC 自动机上数位 dp ,就是在自动机上走 d 步。记状态 \(dp[now][0/1][st][0/1]\) 表示当前走到了自动机的 now 节点,有无达到上界,匹配了的串长为 \(st\) ,有无公共子串。
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define N 100007
#define Mod 1000000007
#define ll long long
int go[N][10],cnt=0,fail[N];
char s[N],c[N];
bool ed[N];
ll f[N][2][51][2];
inline void ins(int l,int r){
int now=0;
for(int i=l;i<=r;i++){
int to=s[i]-'0';
if(!go[now][to])
go[now][to]=++cnt;
now=go[now][to];
}
ed[now]=1;
}
queue<int> Q;
void Get_Fail(){
for(int i=0;i<10;i++)
if(go[0][i]) Q.push(go[0][i]);
while(!Q.empty()){
int u=Q.front(); Q.pop();
ed[u]|=ed[fail[u]];
for(int i=0;i<10;i++)
if(go[u][i]){
fail[go[u][i]]=go[fail[u]][i];
Q.push(go[u][i]);
}else go[u][i]=go[fail[u]][i];
}
}
int d;
ll dfs(int now,bool lim,int st,bool vis){
if(st==d) return vis;
if(~f[now][lim][st][vis]) return f[now][lim][st][vis];
ll ret=0; int rg=lim? c[st]-'0':9;
for(int i=0;i<=rg;i++){
int to=go[now][i];
ret=(ret+dfs(to,lim&(i==rg),st+1,vis|ed[to]))%Mod;
}
return f[now][lim][st][vis]=ret;
return ret;
}
int main(){
scanf("%s",s);
int n=strlen(s);
scanf("%s",c);
d=strlen(c);
for(int i=0;i+d/2-1<n;i++)
ins(i,i+d/2-1);
Get_Fail();
for(int i=d-1;~i;i--)
if(c[i]=='0') c[i]='9';
else{c[i]--;break;}
memset(f,-1,sizeof(f));
int ans=-dfs(0,1,0,0);
scanf("%s",c);
memset(f,-1,sizeof(f));
ans=((dfs(0,1,0,0)+ans)%Mod+Mod)%Mod;
printf("%d",ans);
}
/*
652342365
248
893
*/