康托展开和逆康托展开

康托展开是一个全排列到一个自然数的双射,常用于构建hash表时的空间压缩。设有n个数(1,2,3,4,…,n),可以有组成不同(n!种)的排列组合,康托展开表示的就是是当前排列组合在n个不同元素的全排列中的名次。

逆康托展开给一个数字求出第几个排列组合。

 

给出n和操作数k,要求资瓷: 
P x求n的第x个排列 
Q 一个n的排列 求这是第几个排列 
n<=20

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define N 25
#define LL long long
using namespace std;

int n,k,a[N],vis[N];
LL jc[N];

void solve1()
{
    LL x;
    scanf("%lld",&x);x--;
    memset(vis,0,sizeof(vis));
    for (int i=n-1;i>=0;i--)
    {
        int num=x/jc[i],now=0;x%=jc[i];
        for (int j=1;j<=n;j++)
            if (!vis[j])
            {
                if (now==num)
                {
                    vis[j]=1;printf("%d",j);if (i) cout<<' ';break;
                }
                else now++;
            }
    }
    cout<<endl;
}

void solve2()
{
    for (int i=n;i;i--) scanf("%d",&a[i]);
    LL ans=0;
    for (int i=n-1;i>=0;i--)
    {
        LL s=0;
        for (int j=1;j<=i;j++) if (a[j]<a[i+1]) s++;
        ans+=s*jc[i];
    }
    printf("%lld\n",ans+1);
}

int main()
{
    scanf("%d%d",&n,&k);
    jc[0]=1;
    for (int i=1;i<n;i++) jc[i]=(LL)jc[i-1]*i;
    for (int i=1;i<=k;i++)
    {
        char ch[2];
        scanf("%s",ch);
        if (ch[0]=='P') solve1();
        else solve2();
    }
    return 0;
}

 

posted @ 2018-05-03 23:17  shuai_hui  阅读(172)  评论(0编辑  收藏  举报