题目链接
题解
- 由于
n
n
n 比较大,无法用暴力来做(从小到大枚举所有排列,直到找到第
K
K
K 个)
- 我们可以按位来确定,当确定第
1
1
1 位应该填什么数字的时候,后面
n
−
1
n-1
n−1 位将可以产生
(
n
−
1
)
!
(n-1)!
(n−1)! 种不同的排列,因此我们不是逐一枚举,而是每次跳过
(
n
−
1
)
!
(n-1)!
(n−1)! 个
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
using ll = long long;
const int N = 20;
ll f[N + 5];
bool vis[N + 5];
void solve(int n, ll K) {
memset(vis, 0, sizeof vis);
for (int pos = n; pos; pos--) {
ll sum = 0;
int k = 1;
for (; k <= n; k++) if (!vis[k]) {
if (sum + f[pos - 1] >= K) break;
sum += f[pos - 1];
}
vis[k] = true;
printf("%d%c", k, (pos == 1 ? '\n' : ' '));
K -= sum;
}
}
int main(int argc, char const* argv[]) {
f[0] = 1;
for (int i = 1; i <= N; i++) f[i] = f[i - 1] * i;
int T;
cin >> T;
while (T--) {
int n;
ll K;
cin >> n >> K;
solve(n, K);
}
return 0;
}