【解题报告】 启示录
题目描述
探险队员终于进入了金字塔。通过对古文字的解读, 他们发现,和《圣经》的作者想的一样,古代人认为 666 是属于魔鬼的数。不但如此,只要某数字的十进制表示中 有三个连续的 6,古代人也认为这个是魔鬼的数,比如 666, 1 666, 2 666, 3 666, 6 663, 16 666, 6 660 666 等等,统统是魔 鬼的数。 古代典籍经常用“第 X 大的魔鬼的数”来指代这些数。 这给研究人员带来了极大的不便。为了帮助他们,你需要写一个程序来求出这些魔鬼的数字。
输入格式
输入文件包含多组测试数据。第一行有一个整数 T 表示测试数据的组数。 每组测试数据包含一个整数 X,表示需要求第 X 大的魔鬼的数。
输出格式
对于每组测试数据,在一行内输出结果。
输入输出样例
输入 #1
输出 #1
说明/提示
对于 20% 的数据,保证 X≤10e6。 对于 100% 的数据,保证 T≤1 000,X≤50 000 000。
解题思路
这是一个标准的数位Dp,我们只需要简单地找出他的动态转移方程,然后用试数法(我更乐意叫此为“夹逼法”),就可以得出答案了
AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| #include <iostream> #include <cstdio> #include <algorithm> using namespace std; long long f[21][4]; int t,n,m; void init() { f[0][0]=1; for(int i=0;i<20;i++) { for(int j=0;j<3;j++) { f[i+1][j+1]+=f[i][j]; f[i+1][0]+=f[i][j]*9; } f[i+1][3]+=f[i][3]*10; } } int main() { init(); cin>>t; while(t--) { cin>>n; for(m=3;f[m][3]<n;m++); for(int i=m,k=0;i;i--) { for(int j=0;j<=9;j++) { long long 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; } cout<<j; break; } } } cout<<endl; } return 0; }
|