【解题报告】 启示录

【解题报告】 启示录

题目描述

探险队员终于进入了金字塔。通过对古文字的解读, 他们发现,和《圣经》的作者想的一样,古代人认为 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;
} 
posted @ 2019-09-21 23:20  wweiyi  阅读(209)  评论(0编辑  收藏  举报
js脚本