X表示一个排列在所有的全排列中排第几个(从0开始)。
X=a[0]*(n-1)!+a[1]*(n-2)!+...+a[i]*(i-1)!+...+a[n-1]*0! ,其中a[i]为在当前未出现的元素中是排在第几个(从0开始)(或者说下标i后面值比i这位置值小的个数),这就是康托展开。
逆康托展开就是把X除以(n-1)!得到a[0],然后再对(n-1)!取模,以此类推,分别求出a[0]到a[n-1]。
例题:https://projecteuler.net/problem=24
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) int fac[11]={1,1,2,6,24,120,720,5040,40320,362880,3628800}; bool vis[11]; int main() { ios::sync_with_stdio(false); cin.tie(0); int t=1000000-1; int cnt=9; while(true) { int tt=t/fac[cnt]; int tot=0; for(int i=0;i<=9;i++) { if(!vis[i]) { if(tot==tt)cout<<i,vis[i]=true; tot++; } } t=t%fac[cnt]; cnt--; if(cnt==-1)break; } return 0; }