解法

「長さ$K$の数列であって数列$p$をprefixとして持ちかつ短歌数であるようなものの数$f(K, p)$」が求められれば先頭から順に決めていける(典型)。たぶん$O(\log N)$とかだと思う。

初手$10$進数展開して数列を考える。 とりあえず長さを固定したいので「長さ$K$の数列であって短歌数なものの数」を考え、では次に$\dots$とやれば終了。

二分探索という話も聞こえてきたが実装が面倒なだけでやることは同じな気がする。

実装

#!/usr/bin/env python3
def count_tanka_numbers_of_length(k):
    binomial_9_2 = 9 * 8 // 2
    pattern = 2 ** k - 2
    pattern_with_0 = 2 ** (k - 1) - 1
    return binomial_9_2 * pattern + 9 * pattern_with_0

def count_tanka_numbers_of_length_k_with_prefix(k, prefix):
    kind = len(set(prefix)) 
    if kind == 0:
        return count_tanka_numbers_of_length(k)
    elif kind == 1:
        if 0 in prefix:
            return 0
        pattern = 2 ** (k - len(prefix)) - 1
        return 9 * pattern
    elif kind == 2:
        return 2 ** (k - len(prefix))
    else:
        return 0

def solve(n):
    n -= 1
    acc = 0
    k = 1
    while not (n < acc + count_tanka_numbers_of_length(k)):
        acc += count_tanka_numbers_of_length(k)
        k += 1
    prefix = []
    for _ in range(k):
        for d in range(10):
            if not (n < acc + count_tanka_numbers_of_length_k_with_prefix(k, prefix + [ d ])):
                acc += count_tanka_numbers_of_length_k_with_prefix(k, prefix + [ d ])
            else:
                prefix += [ d ]
                break
        else:
            assert False
    return ''.join(map(str, prefix))

while True:
    n = int(input())
    if n == 0:
        break
    print(solve(n))