HDU 2062 Subset sequence 【好题】

Subset sequence

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3383    Accepted Submission(s): 1730


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
 
 
真的醉了,理解题中的排列花了不少时间。题上说的排列顺序是这样的:比如n=4,1开头的顺序:(1)(1,2)(1,2,3)(1,2,4)(1,2,3,4)(1,2,4)(1,2,4,3)(1,3)(1,3,2)(1,3,2,4)(1,3,4)......而且是按开头数字从大到小的顺序排列的,也就是说开头是1排列完后,才开始排列2开头的。
 
有一个这样的规律:
n=1:1
n=2:(1),(1,2) 每组的个数是f(1)+1; !!! 这里面的f(1)是n=1的总个数,下面的也一样。
(2),(2,1)
n=3:(1),(1,2),(1,2,3),(1,3),(1,3,4) 每组的个数是f(2)+1;
(2),(2,1),(),(),(),
......
一开始用暴力方法不知为什么没过。。。
ac代码如下:
#include<stdio.h>
__int64 f(__int64 n)//n个数可以排列的组合数 
{
    if(n<=1) return n;
    else
    return (f(n-1)+1)*n;
}
int main()
{
    __int64 n,m;
    __int64 i,j;//循环变量 
    __int64 k,fnum;//k表示每组个数,fnum表示每组开头数字 
    __int64 t;//用于输出空格的变量 
    __int64 a[50];
    while(scanf("%I64d%I64d",&n,&m)!=EOF)
    {
        t=0;
        for(i=1;i<=n;i++)
        a[i]=i;
        while(m>0)
        {
            /*找第一位数字*/
            k=f(n-1)+1;
            fnum=m/k+1;
            if(m%k==0) fnum--;//第一个数字 
            if(t>0)
            printf(" "); 
            printf("%d",a[fnum]);//输出第一位数字
            /*把第二位当成第一位继续找*/ 
            for(i=fnum;i<=n;i++)
            {
                a[i]=a[i+1];//输出过的就不能再用了 
            } 
            m-=(fnum-1)*k+1;
            n--;
            t++;
        }
        printf("\n");
    } 
return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值