1. Title link:
POJ-1037
2. The main idea of the topic:
Enter two integers n, c
It is required to output the ** permutation with lexicographic order c from 1 to n.
**Arrangement refers to the arrangement with length n, each number from 1 to n, and the numbers are not repeated and the size is staggered.
3. Analysis:
The "trial method" can be used to determine the ranking of c.
Specifically, we can enumerate the size of the first number
When the first number is a[1], let the number of the ** permutation scheme composed of n-1 numbers be t
If t >= c, then the first number is a[1]
Otherwise, it means that the first number should be larger. In this case, let c-t, a[1] increase by 1.
Repeat the above process to determine the size of the first number, and similarly determine the size of all numbers.
So we should preprocess t first.
f[i][j][k] represents i mutually different numbers, where the leftmost number is ranked j among the i numbers in ascending order, and the leftmost number is low(0)/high( 1) Bits, the number of programs per hour.
The state transition equation is very simple, see the code for details.
PS: When determining the size of the first number, you should first enumerate f[n][j][1], and then enumerate f[n][j][1], because when both meet the conditions When, it is obvious that the lexicographic order with 1 as the high order is smaller.
4. Code implementation:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int M = (int)20;
bool vis[M + 5];
ll f[M + 5][M + 5][2];
void init()
{
f[1][1][0] = f[1][1][1] = 1;
for(int i = 2; i <= M; ++i)
{
for(int j = 1; j <= i; ++j)
{
for(int k = j; k <= i - 1; ++k) f[i][j][0] += f[i - 1][k][1];
for(int k = 1; k <= j - 1; ++k) f[i][j][1] += f[i - 1][k][0];
}
}
}
int main()
{
init();
int T;
scanf("%d", &T);
while(T--)
{
memset(vis, 0, sizeof(vis));
int n; ll c;
scanf("%d %lld", &n, &c);
int ls, k;
for(int j = 1; j <= n; ++j)
{
if(f[n][j][1] >= c)
{
ls = j;
k = 1;
break;
}
else c -= f[n][j][1];
if(f[n][j][0] >= c)
{
ls = j;
k = 0;
break;
}
else c -= f[n][j][0];
}
vis[ls] = 1;
printf("%d", ls);
for(int i = 2; i <= n; ++i)
{
k ^= 1;
int j = 0;
for(int l = 1; l <= n; ++l)
{
if(vis[l]) continue;
++j;
if(k == 0 && ls > l || k == 1 && ls < l)
{
if(f[n - i + 1][j][k] >= c)
{
ls = l;
break;
}
else c -= f[n - i + 1][j][k];
}
}
vis[ls] = 1;
printf(" %d", ls);
}
printf("\n");
}
return 0;
}