康拓展开,逆展开(全排列求第n个)

3 篇文章 0 订阅
1 篇文章 0 订阅

定义:
实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的。

解决问题:
举例由12345–>34251,问34251是全排列的第几个?(按字典序小的开始全排列)

计算方法:
首先我们可以发现由12345–>25431是比较好计算全排列数的,也就可以看成是算由12345–>15432(需要4!次),由21345–>25431(也需要4!次),所以12345–>25431需要2 * 4!次变换,然后我们接着算31245–>32541的全排列数,可以分解成由31245–>31542(需要3!次),和32145–>32541(需要3!次),合起来2 * 3!次,然后12345–>32541的变换次数就是两种情况相加,即2 * 4!+2 * 3!,然后继续算34125–>34152,也就是2!,然后继续算34215–>34215,就是1!,而我们最后一个34251不计算入其中(因为照康拓展开的意思就是这样),那么我们不难发现12345–>34215的变换次数可以合并为2 * 4!+2 * 3!+1 * 2!+1 * 1!+0 * 0!,然后找一波规律,就可以发现刚刚计算得到的全排列个数x,可以表示成x=a[n] * (n-1)!+a[n-1] * (n-2)!+…a[1] * 0!,(a[i]代表第i位数(从右向左数)更右边的数中比第i位数小的数总和)。又由于对于例如计算12345–>34251,34251是全排列第几个的问题,康拓展开求得的是34215是全排列第几个数,所以最后算出的x还需+1才是最终结果。

主要代码:

ll Cantor(string s,int n){
	ll ans=0;
	for(int i=0;i<n;i++){
		ll cnt=0,m=1,temp=1;
		for(int j=i+1;j<n;j++){
			if(s[i]>s[j])
			cnt++;//计后边小于第i个数的个数
			m*=temp,temp++;//m最终保存阶乘结果
		}
		ans+=cnt*m;
	}
	return ans+1;
}

康拓逆展开择日再写。。。
to be continued…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值