http://acm.hdu.edu.cn/showproblem.php?pid=2062
Subset sequence
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3569 Accepted Submission(s): 1802
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
规律:
比如3个的,如果把每种深度视为一大格,那么对于任意深度d(start from 0),
* 第一个一定是空,剩下有n-d个没被使用的数字按照顺序排列,
1 且n-d个数字的小格高度相同
* 明显,我们可以提前处理出这个高度
2 第(n-1)层每个数字占1个高度
* 第(n-2)层每个数字占2个高度,1个空格,1个数字
3 第(n-3)层每个数字有5个高度,1个空格,2个数字
3 ......
* 第i层有:dis[i]=(n-1-i)*dis[i+1]+1
2 所以 dis[i+1]=(dis[i]-1)/(n-1-i)
2 也就是dis[i]=(dis[i-1]-1)/(n-i)
* 处理出来之后,一层层查找确定对应位上的数字即可
1
*
3
3
*
1
3
*
1
*
2
2
*
1
#include <iostream> #include <cstring> using namespace std; typedef unsigned long long ll; int n; ll m; int bit[20],len; bool used[21]; int fnd(int ind){ int ind2=0; for(int i=1;i<21;i++){ if(!used[i]){ if(ind==ind2)return i; ind2++; } } return -1; } ll all; ll dis[21]; int main(){ while(cin>>n>>m){ memset(used,0,sizeof(used)); all =1; ll sub=1; for(int i=0;i<n;i++){ sub*=(n-i); all+=sub; } for(int i=0;i<n;i++){ all--; dis[i]=all/(n-i); all/=(n-i); } len=0; for(int i=n;i>=1;i--,len++){ if(m==0){break;} m--; bit[len]=fnd(m/dis[len]); used[bit[len]]=true; m%=dis[len]; } for(int i=0;i<len;i++){ cout<<bit[i]<<(i==len-1?' ':' '); } } return 0; }