为什么我在EN-WIKI上查不到啊TAT
嗯,康托展开就是一个从n排列集合到自然数集合的映射.
并且这个映射刚好对应了字典序.
比如,设这个函数为C,
那么C{1,2,3}=0,C{3,2,1}=5,C{2,3,1}=3.
用于排列与数字的转换.
使用的时候一定要注意先把排列离散化成0,1,...,n-1的排列再做.
否则要用n^2的时间来找"在全集中比数i小的数个数." 离散化以后直接就是a[i]+1就好做一些.
离散化之后可以用树状数组或者线段树或者平衡树做到nlogn.
#include <cstdio> #include <iostream> #include <fstream> #include <cmath> #include <cstdlib> #include <algorithm> typedef long long ll; typedef unsigned long long ull; typedef unsigned int uint; typedef double db; int getint() { int res=0; char c=getchar(); bool m=false; while(c<'0' || c>'9') m=(c=='-'),c=getchar(); while('0'<=c && c<='9') res=res*10+c-'0',c=getchar(); return m ? -res : res; } const db eps=1e-18; bool feq(db a,db b) { return fabs(b-a)<eps; } using namespace std; int a[50]={0,1,2,3,4,5}; int getpow(int i) { int res=1; while(i>0) res*=i,i--; return res; } int Cantor(int*a,int n) { int res=0; for(int i=0;i<n;i++) { int cnt=0; for(int j=0;j<i;j++) if(a[j]<a[i]) cnt++; res+=getpow(n-i-1)*max(0,a[i]-cnt); } return res; } bool used[50]; int*RevCantor(int X,int n) { int*res=new int[n+1]; memset(used,0,sizeof(bool)*(n+1)); for(int i=0;i<n;i++) { int p=X/getpow(n-i-1); X=X-p*getpow(n-i-1); int j=0; for(;used[j]||p>0;j++) if(!used[j]) p--; res[i]=j; used[j]=true; } return res; } int main() { for(int i=0;i<10;i++) { int c=Cantor(a,6); cout<<i<<' '<<c<<endl; for(int i=0;i<6;i++) cout<<a[i]<<' '; cout<<endl; next_permutation(a,a+6); int*p=RevCantor(c,6); for(int i=0;i<6;i++) cout<<p[i]<<' '; cout<<endl; delete(p); } return 0; }