首页 > 代码库 > hdu(2062)-Subset sequence 组合数学

hdu(2062)-Subset sequence 组合数学

题意:求集合{1,2,3...n}的第m个排列子集合。集合的大小按字典树排。

          例两个元素的排列子集合按字典树排列是:{1},{1,2},{2},{2,1};


解法:一个一个元素来确定,每次把剩余的元素按大小顺序排列在num中,然后根据排列组合原理直接计算下一个位置的元素的大小,直到排列数为0停止;


代码:

/******************************************************
* author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
//freopen ("in.txt" , "r" , stdin);
using namespace std;

#define eps 1e-8
const double pi=acos(-1.0);
typedef long long LL;
const int Max=21;
const int INF=1000000007;
LL A[Max][Max];
LL sum[Max];
void init()
{
    for(int i=0; i<Max; i++)
        for(int j=0; j<=i; j++)
            A[i][j]=j?A[i-1][j-1]*j+A[i-1][j]:1;
    for(int i=0; i<Max; i++)
        for(int j=0; j<=i; j++)
            sum[i]+=A[i][j];
}

int n;
LL m;
int num[Max];
int main()
{
    init();
    while(scanf("%d%I64d",&n,&m)==2)
    {
        for(int i=1; i<=n; i++)
            num[i]=i;
        int len=n;
        int t=(m-1)/sum[len-1]+1;
        printf("%d",num[t]);
        m-=(t-1)*sum[len-1]+1;
        for(int k=t; k<=len-1; k++)
            num[k]=num[k+1];
        len--;
        while(m)
        {
            int t=(m-1)/sum[len-1]+1;
            printf(" %d",num[t]);
            m-=(t-1)*sum[len-1]+1;
            for(int k=t; k<=len-1; k++)
                num[k]=num[k+1];
            len--;
        }
        puts("");
    }
    return 0;
}