• Apocalypse Someday


    POJ

    定义魔鬼的数是数字的十进制表示中至少有三个连续的6,如666,1666,6663,16666,6660666...求第(n(n<=5*10^7))小的魔鬼的数.

    分析:设(f[i][3])表示由i位数字构成的魔鬼树有多少个,设(f[i][j](0<=j<=2))表示由i位数字构成的、开头已经有连续j个6的非魔鬼数有多少个.(允许前导0)

    (f[i][0]=9*(f[i-1][0]+f[i-1][1]+f[i-1][2]))

    (f[i][1]=f[i-1][0],f[i][2]=f[i-1][1])

    (f[i][3]=f[i-1][2]+10*f[i-1][3])

    我们可以先预处理(f)数组.然后对于每个询问n,我们先求出第n小魔鬼数的位数,然后从小到大枚举每一位数字是多少,即可得到这种填法可以得到的魔鬼数的数量,然后与n比较.如果比n小,说明还应该这一位的数字还应该更大,否则当前位就是枚举的该数.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    ll f[21][4];
    inline void prework(){
    	f[0][0]=1;
    	for(int i=1;i<=20;++i){
    		f[i][0]=9*(f[i-1][0]+f[i-1][1]+f[i-1][2]);
    		f[i][1]=f[i-1][0];
    		f[i][2]=f[i-1][1];
    		f[i][3]=f[i-1][2]+10*f[i-1][3];
    	}
    }
    int main() {
    	prework();
    	int T=read();
    	while(T--){
    		int n=read(),m;
    		for(m=3;f[m][3]<n;++m);
    		for(int i=m,k=0;i;--i){
    			for(int j=0;j<=9;++j){
    				ll cnt=f[i-1][3];
    				if(j==6||k==3)
    					for(int l=max(3-k-(j==6),0);l<3;++l)cnt+=f[i-1][l];
    				if(cnt<n)n-=cnt;
    				else{
    					if(k<3){
    						if(j==6)++k;
    						else k=0;
    					}
    					printf("%d",j);
    					break;
    				}
    			}
    		}
    		printf("
    ");
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    用ildasm和ilasm对.net下的exe程序进行破解初探
    随笔--各种概念等等
    C#高级编程学习一-----------------第五章泛型
    visual studio相关操作
    webservice开发
    delphi各种错
    android开发文章收藏
    android开发遇到的问题
    android应用开发基础知道
    数据库各种问题
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11258072.html
Copyright © 2020-2023  润新知