【解题报告】 启示录
【解题报告】 启示录
题目描述
探险队员终于进入了金字塔。通过对古文字的解读, 他们发现,和《圣经》的作者想的一样,古代人认为 666 是属于魔鬼的数。不但如此,只要某数字的十进制表示中 有三个连续的 6,古代人也认为这个是魔鬼的数,比如 666, 1 666, 2 666, 3 666, 6 663, 16 666, 6 660 666 等等,统统是魔 鬼的数。 古代典籍经常用“第 X 大的魔鬼的数”来指代这些数。 这给研究人员带来了极大的不便。为了帮助他们,你需要写一个程序来求出这些魔鬼的数字。
输入格式
输入文件包含多组测试数据。第一行有一个整数 T 表示测试数据的组数。 每组测试数据包含一个整数 X,表示需要求第 X 大的魔鬼的数。
输出格式
对于每组测试数据,在一行内输出结果。
输入输出样例
输入 #1
3
2
3
187
输出 #1
1666
2666
66666
说明/提示
对于 20% 的数据,保证 X≤10e6。 对于 100% 的数据,保证 T≤1 000,X≤50 000 000。
解题思路
这是一个标准的数位Dp,我们只需要简单地找出他的动态转移方程,然后用试数法(我更乐意叫此为“夹逼法”),就可以得出答案了
AC代码
#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;
}
本博文为wweiyi原创,若想转载请联系作者,qq:2844938982