• pjudge#21652[PR #4]到底有没有九【数位dp】


    正题

    题目链接:http://pjudge.ac/problem/21652


    题目大意

    给出一个正整数\(k\),求第\(n\)\(x\)满足\(x\times (10^k-1)\)中没有一个数位为\(9\)

    \(1\leq n\leq 10^{18},1\leq k\leq 18\)


    解题思路

    首先是从高位到低位逐步确定答案,但是直接暴力算乘法肯定很麻烦,我们考虑反过来做。

    我们算第\(n\)个合法的\(x\times (10^k-1)\),然后再除以\(10^k-1\)

    那么现在问题就是给定一些确定的位,求剩下的位有多少种不含\(9\)的组法能够拼出\(10^k-1\)的倍数。

    然后一个数\(10^k-1\)的倍数的条件就是将它每\(k\)位分割一次提出来求和,如果是\(10^k-1\)的倍数就合法。

    段数不会太多,我们可以暴力枚举\(10^k-1\)的倍数,然后数位dp求解。

    细节有点多。


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cctype>
    #define ll __int128
    using namespace std;
    const int W=40;
    int k,a[80],b[80];
    ll n,f[80][10];
    ll read(){
    	ll x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    void print(ll x)
    {if(x>9)print(x/10);putchar(x%10+'0');return;}
    ll solve(){
    	int L=(W+k-1)/k;ll pw=1,ans=0;
    	for(int i=1;i<=k;i++)pw=pw*(ll)10;pw--;
    	for(int d=1;d<=L;d++){
    		ll p=d*pw;
    		for(int i=0;i<k;i++)
    			b[i]=p%10,p/=10;
    		memset(f,0,sizeof(f));f[0][0]=1;
    		for(int i=0;i<k;i++){
    			for(int z=0;z<L;z++)
    				for(int x=(z==0);x<10;x++)
    					f[z/10][z%10]+=f[z][x],f[z][x]=0;
    			for(int j=0;j<L;j++)
    				for(int z=L-1;z>=0;z--)
    					for(int x=9;x>=0;x--){
    						if(!f[z][x])continue;
    						ll r=f[z][x];f[z][x]=0;
    						if(a[j*k+i]==-1)
    							for(int y=8;y>=0;y--)
    								f[z+(x+y)/10][(x+y)%10]+=r;
    						else 
    							f[z+(x+a[j*k+i])/10][(x+a[j*k+i])%10]+=r;
    					}
    			for(int z=0;z<L;z++)
    				for(int x=0;x<10;x++)
    					if(x!=b[i])f[z][x]=0;
    		}
    		for(int x=0;x<10;x++)ans+=f[p][x];
    	}
    	return ans;
    }
    signed main()
    {
    	k=read();n=read();
    	ll now=0,las;int m=(W+k-1)/k*k;
    	for(int i=0;i<m;i++)a[i]=-1;
    	for(int i=m-1;i>=0;i--){
    		a[i]=0;now+=(las=solve());
    		while(now<n){
    			a[i]++;
    			now+=(las=solve());
    		}
    		now-=las;
    	}
    	ll ans=0;//print(now);
    	for(int i=m-1,flag=0;i>=0;i--)
    		ans=ans*(ll)10+a[i];
    	ll pw=1;
    	for(int i=0;i<k;i++)pw=pw*(ll)10;
    	pw=pw-1;ans/=pw;
    	print(ans);
    	return 0;
    }
    //1 8
    
  • 相关阅读:
    执行上下文和作用域,作用域链
    学习笔记一:定位
    exports和module.exports的区别——学习笔记
    伪类和伪元素
    visibility和display
    CSS选择器,层叠
    Servlet乱码处理-------续集
    Servlet的乱码处理手记
    前端框架之Semantic UI
    最完整的Oracle11g 概述
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/16482586.html
Copyright © 2020-2023  润新知