Problem Description
Consider the aggregate An= { 1, 2, …, n }. For example, A1={1}, A3={1,2,3}. A subset sequence is defined as a array of a non-empty subset. Sort all the subset sequece of An in lexicography order. Your task is to find the m-th one.
Input
The input contains several test cases. Each test case consists of two numbers n and m ( 0< n<= 20, 0< m<= the total number of the subset sequence of An ).
Output
For each test case, you should output the m-th subset sequence of An in one line.
Sample Input
1 1
2 1
2 2
2 3
2 4
3 10
Sample Output
1
1
1 2
2
2 1
2 3 1
思路
用dp来找到规律
a[i] = a[i - 1] * (i - 1) + 1
1 2 5 16 。。。
以3 10举例
现在序列{1,2,3}
现在是3个5种小情况组成的15种情况
1
12
123
13
132(5)
2
21
213
23
231(5)
3
31
312
32
321(5)
首先10是第二组中的数
m -= (d - 1) * a[n] + 1;//d:第d组数(上一行我们知道是第二组)
10-(15+1)=4
输出a[2]=2并从序列中拿出
序列中:{1,3}
现在是两个2种小情况组成的4种情况
1
13(2)
3
31(2)
4是第二组中的数
4-(12+1)=1
输出a[1]=1并从序列中拿出
序列中:{3}
1是第一组中的数
1-(0*1+1)=0
输出a[1]=3并从序列中拿出
序列为空,程序结束
输出结果为2 1 3
程序代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
#include<set>
#include<iomanip>
typedef long long l;
using namespace std;
int main()
{
l a[25] = { 0 };
a[1] = 1;
a[2] = 2;
for (int i = 3; i < 21; i++)
{
a[i] = a[i - 1] * (i - 1) + 1;//每个n子列序列的数量/n
}
l n, m;
while (cin >> n >> m)
{
bool first = true;
l b[25] = { 0 };//子集序列,可以在里面删除数据
for (int i = 1; i <= n; i++)
{
b[i] = i;
}
if (m == 1)
{
cout << "1" << endl;
continue;
}
while (n && m)
{
l c = m % a[n];//是否求余为0
l d = m / a[n];//子列序列中的第几个
if (c)d++;//如果求余不为0,则d要加一
if (!first)cout << " ";
cout << b[d];
for (int i = d; i < n; i++)
{
b[i] = b[i + 1];//将输出上的数据删除(让后面的数据覆盖前面的数)
}
m -= (d - 1) * a[n] + 1;//是子列序列中第d个子列序列中的第几个
n--;
first = false;
}
cout << endl;
}
return 0;
}