CF585F Digits of Number Pi

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
*/
posted @ 2021-02-19 10:30  Kreap  阅读(42)  评论(0编辑  收藏  举报