HDU1027 Ignatius and the Princess II( 逆康托展开 )


**链接:****传送门 **

题意:给出一个 n ,求 1 ~ n 全排列的第 m 个排列情况

思路:经典逆康托展开,需要注意的时要在原来逆康托展开的模板上改动一些地方。

  • 分析:已知 1 <= M <= 10000,10000 < 8!,根据逆康托展开的原理可以发现,A[n] * (n-1)! + A[n-1] * (n-2)! + A[n-2] * (n-3)! + ...... + A[2] * 1! + A[1] * 0! ,在前 n - 8 项之前,Ai == 0,所以每次都是取剩余排列中第 0 个最大元素,也就是 0 1 2 3 ... n - 9( 从0开始 ),后面的项直接按照逆康托计算得到。

/*************************************************************************
    > File Name: hdu1027.cpp
    > Author:    WArobot 
    > Blog:      http://www.cnblogs.com/WArobot/ 
    > Created Time: 2017年05月18日 星期四 16时13分40秒
 ************************************************************************/

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define cls(x) memset(x,0,sizeof(x))
const int MAX_N = 1010;		// 排列长度
const int MAX_C = 9;		// 需要的最大阶乘N!
ll fac[MAX_C];
 
// 初始化阶乘系数
void init_fac(){
	fac[1] = fac[0] = 1;
	for(int i = 2 ; i < MAX_C ; i ++)		fac[i] = fac[i-1]*(ll)i;
}
// 寻找由1~n组成全排列按字典序排序后第x个排列
void uCT(int n,int x){
	bool vis[MAX_N];	cls(vis);
	int  ans[MAX_N];	cls(ans);
 	x--;
 	int i , j;
 	for(i = 0 ; i < n ; i++){
		if( i >= n - 8 ){
			int t = x/fac[n-i-1];		// 每次都寻找第t大的数
			for(j = 0 ; j < n ; j++){
				if(!vis[j]){
					if( t == 0 )	break;	
					t -- ;
				}
			}
			ans[i] = j;
			vis[j] = 1;
			x %= fac[n-i-1];
		}
		else{
			ans[i] = i;
			vis[i] = 1;
		}
 	}
 	for(i = 0 ; i < n-1 ; i++)	printf("%d ",ans[i] + 1);
	printf("%d
",ans[n-1]+1);
}

int main(){
	int n , x;
	init_fac();
	while(~scanf("%d%d",&n,&x)){
		uCT(n,x);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/WArobot/p/6874777.html