POJ 3208 启示录
Posted cjc030205
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 3208 启示录相关的知识,希望对你有一定的参考价值。
POJ 3208 启示录
有一个直接的想法是确定(x)个666数的位数,然后一位一位试着从高位往低位填
这样的话需要处理一个从低位往高位计666数的预处理
设(f_{i,0/1/2/3})表示从低往高填到第(i)位,末尾有(0/1/2/3)个6的数的个数
再考虑预处理完了搞出位数之后怎么一步一步填
假设第(x)个666数有(tmp)位,当前从高往低填到第(i)位,枚举这位填(j),之前已经有了连续的(k)个6
有两种可能,一种是当前位可以填(j),也就是这一位填(j)时能产生的666数不少于要求的个数
如果当前位不能填(j),那么就是这一位填(j)时产生的666数不满足要求的个数,得考虑填个更大的数
考虑在之前填完的连续的(k)的个数,明显也只能在可以填的时候更新。
#include<cstdio>
#include<cstring>
#include<cmath>
const int N = 2e2+7;
#define R register
typedef long long LL;
LL f[N][5];
inline int max(int a, int b) {
return a > b ? a : b;
}
int main() {
f[0][0] = 1;
for (R int i = 1; i <= 20; i++) {
f[i][0] = 9LL * (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] + 10LL * f[i - 1][3];
}
int n, T;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
int tmp = 3;
while (f[tmp][3] < n) tmp++;
for (R int i = tmp, k = 0; i > 0; i--) {
//LL res = f[i - 1][3];
for (R int j = 0; j <= 9; j++) {
LL res = f[i - 1][3];
if (j == 6 || k == 3)
for (R int o = max(3 - (j == 6) - k, 0); o < 3; o++)
res += f[i - 1][o];
if (res < n)
n -= res;
else {
if (k < 3) {
if (j == 6) k++;
else k = 0;
}
printf("%d", j);
break;
}
}
}
puts("");
}
}
以上是关于POJ 3208 启示录的主要内容,如果未能解决你的问题,请参考以下文章
poj3208 Apocalypse Someday 数位dp+二分 求第K(K <= 5*107)个有连续3个6的数。