康托展开是一个全排列到一个自然数的双射,常用于构建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 ",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; }