zoukankan      html  css  js  c++  java
  • Codeforces 585F. Digits of Number Pi 题解

    题目链接:F. Digits of Number Pi

    题目大意:洛谷


    题解:观察到(n,d)都很小,所以我们可以把(s)中所有长度为(left lfloor frac{d}{2} ight floor)的子串全部拿出来建一个 AC 自动机,然后将限制差分一下改成小于等于一个数的有多少个,然后直接跑一遍非常暴力的数位 DP 即可。

    更加具体的,设状态(f_{i,j,0/1,0/1})表示当前 DP 到第(i)为,在自动机上的节点编号为(j),是否达到上界,是否出现长度为(left lfloor frac{d}{2} ight floor)的子串的字符串个数,时间复杂度为(O(ncdot d^2cdot S))(S)为字符集大小)。

    代码:

    #include <queue>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int Maxn=1000;
    const int Maxd=50;
    const int Mod=1000000007;
    struct Node{
    	int ch[10];
    	int dep,fail;
    }node[Maxn*Maxd+5];
    int id_tot;
    char s[Maxn+5],x[Maxn+5],y[Maxn+5];
    int n,d;
    void add(char *s,int len){
    	int root=0;
    	for(int i=1;i<=len;i++){
    		if(node[root].ch[s[i]]==0){
    			node[root].ch[s[i]]=++id_tot;
    			node[id_tot].dep=node[root].dep+1;
    		}
    		root=node[root].ch[s[i]];
    	}
    }
    void init_bfs(){
    	queue<int> q;
    	for(int i=0;i<10;i++){
    		if(node[0].ch[i]){
    			q.push(node[0].ch[i]);
    			node[node[0].ch[i]].fail=0;
    		}
    	}
    	while(!q.empty()){
    		int u=q.front();
    		q.pop();
    		for(int i=0;i<10;i++){
    			if(node[u].ch[i]==0){
    				node[u].ch[i]=node[node[u].fail].ch[i];
    			}
    			else{
    				node[node[u].ch[i]].fail=node[node[u].fail].ch[i];
    				q.push(node[u].ch[i]);
    			}
    		}
    	}
    }
    int f[Maxd+5][Maxn*Maxd+5][2][2];
    int calc(char *s,int len){
    	memset(f,0,sizeof f);
    	f[0][0][1][0]=1;
    	for(int i=0;i<len;i++){
    		for(int j=0;j<=id_tot;j++){
    			for(int a=0;a<=1;a++){
    				for(int b=0;b<=1;b++){
    					if(f[i][j][a][b]==0){
    						continue;
    					}
    					for(int k=0;k<10;k++){
    						if(a==1&&k>s[i+1]){
    							break;
    						}
    						int &tmp=f[i+1][node[j].ch[k]][a&(k==s[i+1])][b|(node[node[j].ch[k]].dep==(len>>1))];
    						tmp=(tmp+f[i][j][a][b])%Mod;
    					}
    				}
    			}
    		}
    	}
    	int ans=0;
    	for(int i=0;i<=id_tot;i++){
    		ans=(ans+f[len][i][1][1])%Mod;
    		ans=(ans+f[len][i][0][1])%Mod;
    	}
    	return ans;
    }
    int main(){
    	scanf("%s",s+1);
    	while(s[++n]!='');
    	n--;
    	scanf("%s",x+1);
    	while(x[++d]!='');
    	d--;
    	scanf("%s",y+1);
    	for(int i=1;i<=n;i++){
    		s[i]-='0';
    	}
    	for(int i=1;i<=d;i++){
    		x[i]-='0';
    		y[i]-='0';
    	}
    	for(int i=1;i<=(n-(d>>1)+1);i++){
    		add(s+i-1,d>>1);
    	}
    	init_bfs();
    	x[d]--;
    	int tmp=d;
    	while(x[tmp]<0){
    		x[tmp-1]--;
    		x[tmp]=9;
    		tmp--;
    	}
    	printf("%d
    ",(calc(y,d)-calc(x,d)+Mod)%Mod);
    	return 0;
    }
    
  • 相关阅读:
    Centos warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
    gitlab安装与配置(Centos6.8)
    重装MAC系统 “安装器有效负载签名检查失败” 解决方法
    nginx配置限制同一个ip的访问频率
    nginx配置文件详解
    C# 获取打印机列表以及串口
    JQ将数组转换为Json
    快速查看SQL Server 中各表的数据量以及占用空间大小
    键盘unicode值对照表
    JavaScript经典代码【二】【javascript判断用户点了鼠标左键还是右键】
  • 原文地址:https://www.cnblogs.com/withhope/p/13608600.html
Copyright © 2011-2022 走看看