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("");
}
}