题目大意
求第x个Decibinary Number,顺序为先按其十进制的值升序再按字面值升序。
简要题解
dp,设$f[i][j]$表示值为i,长度为j时的DN数目,然后就显然了。
注意dp第二维大小的设置,有10000...00这种DN存在,故而第二维大小应该是$log_2(sum_{i=0}^{15}9 imes 2^i)$
输出答案就按高位到低位枚举。
脑抽:感觉自己是不是不太愿意长时间深入思考,想了一会就会开小差,一个傻逼题也磨蹭了好久orz
get一个点,不能有前导0的处理:之前枚举1-9,但后面的转移需要用前缀和考虑所有比自己短的可能。
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef double DB; LL f[300005][20], a[300005][20], b[300005]; void print(LL x, int v, int l) { if (l == 0) return ; for (int i = 0; i <= 9; ++i) { int nv = v - i * (1<<(l-1)); if (x - a[nv][l - 1] <= 0) { putchar('0' + i); print(x, nv, l - 1); break; } else x -= a[nv][l - 1]; } } int main() { #ifdef lol freopen("dn.in", "r", stdin); freopen("dn.out", "w", stdout); #endif f[0][1] = 1; for (int i = 0; i < 20; ++i) a[0][i] = 1; b[0] = 1; for (int i = 1; i < 300005; ++i) { for (int j = 1; j < 20; ++j) { for (int k = 1; k <= 9; ++k) if (k * (1<<(j-1)) <= i) f[i][j] += a[i - k * (1<<(j-1))][j - 1]; a[i][j] = a[i][j - 1] + f[i][j]; } b[i] = a[i][19] + b[i - 1]; } int q; LL x; scanf("%d", &q); while (q--) { scanf("%lld", &x); int l = 0, r = 300000, m, w = -1, p = 1; while (l <= r) { m = (l + r) >> 1; if (b[m] < x) { l = m + 1; } else { w = m; r = m - 1; } } assert(w != -1); if (w != 0) x -= b[w - 1]; for (LL c = 0; p < 20; c += f[w][p], ++p) if (x <= c) break; print(x, w, p - 1); puts(""); } return 0; }