#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

LL f[31][4];
int n;

void init()
{
    f[0][0] = 1;
    for(int i = 1; i <= 20; i++)
    {
        f[i][0] = (f[i - 1][0] + f[i - 1][1] + f[i - 1][2]) * 9;
        f[i][1] = f[i - 1][0];
        f[i][2] = f[i - 1][1];
        f[i][3] = f[i - 1][3] * 10 + f[i - 1][2];
    }
}

int main()
{
    int t;
    cin >> t;

    init();

    while(t --)
    {
        cin >> n;
        int len = 3;
        while(f[len][3] < n) len ++; //确定位数

        LL now = 0;
        for(int i = len; i >= 1; i --)
        {
            for(int j = 0; j <= 9; j++)
            {
                LL cnt = f[i-1][3];
                
                if(now == 3 || j == 6) //现在存在多少个魔鬼数
                {
                    int kk = max((LL)0, 3 - now - (j == 6));
                    for(int k = kk; k <= 2; k ++)
                        cnt += f[i - 1][k];
                }

                if(cnt < n) n -= cnt;
                else {
                    if(now < 3) {
                        if(j == 6)
                            now ++;
                        else now = 0;
                    }
                    cout << j;
                    break;
                }
                
            }
        }
        cout << endl;
    }
    return 0;
}

/*
试填法

状态表示:f[i][j]:当前的数有i位。
j=0表示最后一位不是6
j=1表示最后一位是6,但前一位不是
j=2 表示当前的6连在一起的有两个
j=3 表示已经凑出来一个魔鬼数

状态计算: f[i][0] = (f[i - 1][0] + f[i - 1][1] + f[i - 1][2]) * 9
f[i][j] = f[i - 1][j - 1]
f[i][3] = f[i - 1][3] * 10 + f[i - 1][2];


利用试填法:
先确定位数len

对于每一位i, 从高到低,枚举当前位数p
1.cnt表示我们如果把这一位赋值为p的魔鬼数的方案数,cnt = f[i-1][3]
2.如果当前数位6的后继,或者我们已经有了一个魔鬼数后缀,那么cnt += 当前前缀的方案数
3.cnt < n , 将n减去cnt,继续枚举这一位的取值。
4.cnt >= n, 说明这一位就是p,输出p,然后更新连续6的个数。i++

*/

0 条评论

目前还没有评论...