• poj3208


    题面:

    古代人认为666是属于魔鬼的数。

    不但如此,只要某数字的十进制表示中有三个连续的6,古代人也认为这是个魔鬼的数,比如666,1666,6663,16666,6660666等等。

    古代典籍中经常用“第X小的魔鬼的数”来指代这些数,这给研究人员带来了极大的不便。

    现在请编写一个程序,可以实现输入X,输出对应的魔鬼数。

    输入格式

    第一行包含整数T,表示共有T组测试数据。

    每组测试数据占一行,包含一个整数X。

    输出格式

    每组测试数据占一行,输出一个魔鬼数。

    数据范围

    1T10001≤T≤1000,
    1X51071≤X≤5∗107

    输入样例:

    3
    2
    3
    187
    

    输出样例:

    1666
    2666
    66666
    题解:
    设f[i][3]表示由i位数字构成的魔鬼数有多少,f[i][j](0<=j<=2)表示由i位数字构成的,开头已经由连续j个6的非魔鬼数有多少个。在计算f的时候,允许前导0的存在。
    考虑第i位(最高位)是什么数字,容易得到转移方程
    f[i][0]=9*(f[i-1][0]+f[i-1][1]+f[i-1][2])//但i位前面无连续的6时,i-1位前有几个都可以,第i位可以填除6以外的任何数
    f[i][1]=f[i-1][0]//第i位填6
    f[i][2]=f[i-1][1]//第i位填6
    f[i][3]=f[i-1][2](第i位填6)+10*f[i-1][3](第i位填任何数)
    然后通过“试填法“从最高位一位一位确定具体的数,同时记录当前末尾已经有连续的k个6(可以与开头由3-k的非魔鬼数构成新的魔鬼数统计进去)
    从小到大枚举当前位填什么数字,通过预处理的F数组可以直接计算出后边的数位有多少种填法可以得到魔鬼数,与x比较即可
    代码:
     1 #include<iostream>
     2 #include<cstring>
     3 #include<cmath>
     4 using namespace std;
     5 long long f[21][4];
     6 int t,n,m;
     7 void pre_work()
     8 {
     9     f[0][0]=1;
    10     for(int i=0;i<20;i++)
    11     {
    12         for(int j=0;j<3;j++)
    13         {
    14         f[i+1][j+1]+=f[i][j];
    15         f[i+1][0]+=9*f[i][j];
    16        }
    17        f[i+1][3]+=f[i][3]*10;
    18     }
    19 }
    20 int main()
    21 {
    22     pre_work();//预处理
    23     scanf("%d",&t);
    24     //cin>>t;
    25     while(t--)
    26     {
    27         //printf("%lld
    ",f[3][3]);
    28         scanf("%d",&n);
    29         for(m=3;f[m][3]<n;m++);//确定位数
    30         for(int i=m,k=0;i;i--)
    31         {
    32             for(int j=0;j<=9;j++)
    33             {
    34                 long long cnt=f[i-1][3];//i-1位魔鬼数
    35                 if(j==6||k==3)//求由前l(0<=l<=2)个6开头的非魔鬼数与已经出现的3-l个6构成的魔鬼数个数
    36                 for(int l=max(3-k-(j==6),0);l<3;l++)
    37                 cnt+=f[i-1][l];
    38                 if(cnt<n)
    39                 n-=cnt;
    40                 else
    41                 {
    42                     if(k<3)//如果已经出现了连续的3个6均可构成魔鬼数
    43                     {
    44                         if(j==6)k++;
    45                         else
    46                         k=0;
    47                     }
    48                     printf("%d",j);
    49                     break;
    50                 }
    51             }
    52         }
    53         printf("
    ");
    54     }
    55      return 0;
    56 }
  • 相关阅读:
    不怕上不了 Android developers
    不花钱的可靠性设计
    linux2.6 内核特性配置
    Linux动态库的编译与使用 转载
    多线程使用互斥锁的C范例
    TSLIB 分析
    Notepad++中文版下载 以及HEX显示
    C程序实现在lcd 上全屏写 blue 色 及获取fb信息
    pthread_cond_wait的spurious wakeup问题
    查看linux内存条数的命令与清理内存使用
  • 原文地址:https://www.cnblogs.com/flyljz/p/11727507.html
Copyright © 2020-2023  润新知