康托展开
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 int x[25],ans[25],j; 6 long long f[25]={1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,6227020800,87178291200,1307674368000,20922789888000,355687428096000,6402373705728000,12164510040883200};//0-19的阶乘(factorial) 7 long long cantor(int n,int *a){ 8 long long total,sum=0; 9 for(int i=0;i<n;i++){ 10 total=0;//记录比char[a]大的数的个数(未出现的) 11 for(int j=i+1;j<n;j++) 12 if(a[i]>a[j]) 13 total++; 14 sum+=total*f[n-1-i];//计算a[i]是1-n的全排列中第几个出现的 15 } 16 return sum+1; 17 } 18 //1-n的全排列,s排在第k小 19 void ni_cantor(int n,long long k){ 20 long long t; 21 bool vis[25];//记录1-n是否已经出现过 22 memset(vis,0,sizeof(vis)); 23 k--; 24 for(int i=0;i<n;i++){ 25 t=k/f[n-1-i];//不断/n-1-0的阶乘,得到未出现的数中比第i+1位(从左)小的数的个数 26 for(j=1;j<=n;j++)//s[i]是1-n中未出现的第t+1小的数 27 if(!vis[j]){ 28 if(t==0) 29 break; 30 t--; 31 } 32 ans[i]=j; 33 vis[j]=1; 34 k%=f[n-1-i];//取mod继续 35 } 36 } 37 int main(){ 38 int n; 39 long long m; 40 scanf("%d%lld",&n,&m); 41 for(int i=0;i<n;i++) 42 scanf("%d",&x[i]); 43 printf("%lld\n",cantor(n,x)); 44 ni_cantor(n,m); 45 for(int i=0;i<n-1;i++){ 46 printf("%d ",ans[i]); 47 } 48 printf("%d",ans[n-1]); 49 return 0; 50 }