• CF585F Digits of Number Pi


    还没写,不一定对。/cy

    一个 \(naive\) 的想法,暴力枚举 s 的子串,然后找 \([x,y]\) 有多少个子串。但找的话似乎很难实现,直接对 s 建 SAM,之后数位 dp 时记录下现在匹配到哪个节点即可。

    我们发现,枚举是不必要的,我们只需要在数位 dp 时记录能匹配到长度多少,对于匹配到长度为 \(\lfloor \dfrac{d}{2}\rfloor\) ,那么后面无论怎样都是可以贡献的,打标记跑下去。边界时看看有没有标记即可。

    相信 SAM 上匹配子串已经成了人均,所以不写了。

    \(\text{Code}\)

    没想到我 WA on #10竟然因为 dp 过程忘记取模了。

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <map>
    
    #define ll long long
    
    using namespace std;
    int rd() {
    	int f=1,sum=0; char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    ll lrd() {
    	ll f=1,sum=0; char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    
    const int N=(int)(4e3+5),mod=(int)(1e9+7);
    int n,son[10][N],len[N],fa[N],tot=1,las=1;
    int cnt,num[60],d;
    char s[N],s2[N];
    
    int ins(int c) {
    	if(son[c][las]) {
    		int pre=las,y=son[c][pre];
    		if(len[y]==len[pre]+1) return y;
    		int x=++tot; len[x]=len[pre]+1;
    		fa[x]=fa[y]; fa[y]=x;
    		for(int i=0;i<10;i++) son[i][x]=son[i][y];
    		for(;pre&&son[c][pre]==y;pre=fa[pre]) son[c][pre]=x;
    		return x;
    	}
    	int x=++tot,pre=las; len[x]=len[pre]+1;
    	for(;pre&&!son[c][pre];pre=fa[pre]) son[c][pre]=x;
    	int y=son[c][pre];
    	if(!pre) fa[x]=1;
    	else if(len[pre]==len[y]+1) fa[x]=y;
    	else {
    		int p=++tot; len[p]=len[pre]+1;
    		fa[p]=fa[y]; fa[x]=fa[y]=p;
    		for(int i=0;i<10;i++) son[i][p]=son[i][y];
    		for(;pre&&son[c][pre]==y;pre=fa[pre]) son[c][pre]=p;
    	}
    	return x;
    }
    
    void solve(int &pos,int c,int &le) {
    	while(pos!=1&&!son[c][pos]) pos=fa[pos],le=len[pos];
    	if(son[c][pos]) pos=son[c][pos],++le;
    	else le=0;
    }
    
    ll f[2][60][60][N];
    ll dfs(int lim,int zero,int fl,int x,int le,int pos) {
    	if(!x) return fl;
    	if(!lim&&!zero&&~f[fl][x][le][pos]) return f[fl][x][le][pos];
    	int nex=lim?num[x]:9; ll res=0;
    	for(int i=0;i<=nex;i++) {
    		if(fl) {
    			res+=dfs(lim&(i==nex),zero&(!i),fl,x-1,le,pos),res%=mod; continue;
    		}
    		int ppos=pos,lee=le; solve(ppos,i,lee);
    		//cout<<lee<<" "<<cnt/2<<endl;
    		res+=dfs(lim&(i==nex),zero&(!i),fl|(lee>=(d/2)),x-1,lee,ppos),res%=mod;
    	}
    	if(!lim&&!zero) f[fl][x][le][pos]=res;
    	return res;
    }
    
    ll solve() {
    	cnt=strlen(s2+1); for(int i=1;i<=cnt;i++) num[i]=s2[cnt-i+1]-'0';
    	return dfs(1,1,0,cnt,0,1);
    }
    
    int main() {
    	scanf("%s",s+1); n=strlen(s+1);
    	for(int i=1;i<=n;i++) las=ins(s[i]-'0');
    	ll ans=0;
    	memset(f,-1,sizeof(f));
    	scanf("%s",s2+1); d=cnt=strlen(s2+1); s2[cnt--]--;
    	while(s2[cnt]-'0'==-1) s2[cnt]--,s2[cnt--]=9+'0';
    	ans-=solve();
    	scanf("%s",s2+1); ans+=solve();
    	ans=(ans%mod+mod)%mod; printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    听说,好久不更了......
    JavaScript中数组常用方法
    html5常用英语单词
    重写与重载的区别
    RelativeLayout以及ListView
    树莓派基础配置
    通过yum安装lnmp-phpmyadmin
    POJ1850
    基于字典序的组合生成算法
    全排序之字典排序
  • 原文地址:https://www.cnblogs.com/xugangfan/p/15872346.html
Copyright © 2020-2023  润新知