题意:从所有数字出现次数均不超过 t t t 次的16进制数中找到第 k k k 小个数是多少。
思路:显然,由于
k
k
k 的最大不超过2e9 ,所以这个答案的位数不会超过9位,那么我们可以先枚举每个位数下满足题目要求的十六进制数的个数,找到答案的位数,然后从高位到低位枚举即可。
对于每种长度的数目个数可以暴力求得,设一个数组
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示 前
i
i
i 个数使用了
j
j
j 个位置的方法数。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define PI acos(-1)
#define INF 0x3f3f3f3f
#define NUM 200010
#define debug true
#define lowbit(x) ((-x) & x)
#define ffor(i, d, u) for (int i = (d); i <= (u); ++i)
#define _ffor(i, u, d) for (int i = (u); i >= (d); --i)
#define mst(array, Num, Kind, Count) memset(array, Num, sizeof(Kind) * (Count))
const int P = 1e9 + 7;
template <typename T>
void read(T &x)
{
x = 0;char c;T t = 1;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-'){t = -1;c = getchar();}
do(x *= 10) += (c - '0');while ((c = getchar()) >= '0' && c <= '9');
x *= t;
}
template <typename T>
void write(T x)
{
int len = 0;char c[21];
if (x < 0)putchar('-'), x *= (-1);
do{++len;c[len] = (x % 10) + '0';} while (x /= 10);
_ffor(i, len, 1) putchar(c[i]);
}
int t;
ll k, c[15][15];
ll dp[16][20];
int limit[16];
char num[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
ll check(const int &len)
{
memset(dp, 0, sizeof(dp));
ffor(i, 0, min(limit[0], len)) dp[0][i] = c[len][i];
ffor(i, 1, 15)
ffor(j, 0, len)
ffor(z, 0, min(limit[i], j))
dp[i][j] += (dp[i - 1][j - z] * c[len - j + z][z]);
return dp[15][len];
}
void AC()
{
read(k), read(t);
c[0][0] = c[1][0] = c[1][1] = 1;
ffor(i, 2, 14)
{
c[i][0] = c[i][i] = 1;
ffor(j, 1, i - 1)
c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
}
ffor(i, 0, 15) limit[i] = t;
int len = 1;
ll ans;
for (;; ++len)
{
ans = 0;
if(len == 1)
ans = 15;
else
ffor(i, 1, 15)
{
--limit[i], ans += check(len - 1);
++limit[i];
}
if (ans < k)
k -= ans;
else
break;
}
_ffor(i, len, 1)
{
ffor(j, 0, 15)
{
if (i == len && j == 0)
continue;
if (limit[j] == 0)
continue;
--limit[j];
if ((ans = check(i - 1)) >= k)
{
putchar(num[j]);
break;
}
k -= ans, ++limit[j];
}
}
}
int main()
{
AC();
return 0;
}