Decibinary Numbers

题目大意

求第x个Decibinary Number,顺序为先按其十进制的值升序再按字面值升序。

简要题解

dp,设$f[i][j]$表示值为i,长度为j时的DN数目,然后就显然了。

注意dp第二维大小的设置,有10000...00这种DN存在,故而第二维大小应该是$\log_2(\sum_{i=0}^{15}9\times 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;
}

 

posted @ 2017-07-12 14:36  ichneumon  阅读(382)  评论(0编辑  收藏  举报