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
Sample Output
规律:
比如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?'\n':' ');
}
}
return 0;
}