由题目可知An的子集是可重复的,所以可以把每个首个元素相同的子集归为一个子集块,而每个每个子集块所包含的子集个数相同。
通过运算可知A1=1,A2=2,A3=5,A4=16
因而得出规律:An=An-1*(n-1)+1。
接下来每次操作都寻找所求子集am的第一个元素所在的子集块并输出首个元素,之后从集合中排出该元素。并以此类推求出所求子集。
代码如下:
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
int main()
{
__int64 a[21];
a[0]=0;
a[1]=1;
for(int i=2;i<=20;i++)
{
a[i]=a[i-1]*(i-1)+1;
}//计算集合Ai有多少个子集块
int n;
__int64 m;
while(scanf("%d%I64d",&n,&m)!=EOF)
{
int b[21];
for(int i=0;i<=n;i++)
b[i]=i;
while(m!=0&&n--)
{
int k=m/a[n+1];//找到子集第一个元素所在子集块的位置
if(m%a[n+1]!=0)k++;
printf("%d",b[k]);
for(int i=k;i<=n;i++)
b[i]=b[i+1];//排除子集中已经输出的元素
m-=(k-1)*a[n+1]+1;//m减去当前子集块之前的所有子集的个数
if(m==0)printf("\n");//运行结束
else printf(" ");//寻找下一个元素
}
}
return 0;
}