康托展开&&逆康托展开 (C++小白版)

本文介绍了康托展开的概念,它是一个全排列到自然数的双射,常用于哈希表空间压缩。康托展开值是通过计算排列在全排列中的顺序得出的,可以通过累加每个数之前未出现且更小的数的个数来得到。逆康托展开则是通过已知顺序反推出排列。文章提供了简单的C++实现,并解释了算法的时间复杂度。
摘要由CSDN通过智能技术生成

和许多数论小白一样,每次做到数论题都是一脸懵逼 ,于是便刷起来数论题,没想到第一道入门题就看不懂题意,看到标签要用到康托展开。
这是个什么鬼?听都没听过。 于是就查了一下百度。

康托展开

link [百度]康托展开
百度上是这样介绍的:

康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩。

… …好像看不懂,不过后面又说到了它的实质:

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

于是就理解了题意:第一行输入一个数n,第二行输入一个排列。输出这个排列在n的全排列中的顺序。

那道入门题也就是康托展开的模板题。
举个栗子:
3的全排列是(按字典序从小到大):
123 —1
132 —2
213 —3
231 —4
312 —5
321 —6
排列“231”在3的全排列中是第四小,所以“231”的康托展开值为4。

那这个康托展开值是怎么得出的呢?

a数组记录每个数之前没有出现且比当前数小的数的个数(a[i]表示第(n-i+1)个数)
排列231的第一位是2,比2小的数且之前没有出现过的数有一个:1。则a[3]=1 (a[3]记录第一位);
第二位是3,比3小的数且之前没有出现过的数有一个:1。则a[2]=1 (a[2]记录第二位);
第三位是1,比1小的数且之前没有出现过的数有零个。则a[1]=0 (a[1]记录第三位);

在这里插入图片描述
康托展开值 = X+1 = a[3] * 2!+a[2] * 1!+a[1] * 0!+1=1* 2+1* 1+0+1=4;

那为什么这样是对的呢?

我们知道对于m位数的全排列有m!个排列。(第一个数有m种选择,第二个数有(m-1)种选择,……,第m个数有1种选择,因此总方案数有:m*(m-1)*(m-2) *……*2 *1即m!种)

对于要求的排列231从第一个数开始,比2小且前面没有出现的数有:1,说明231是在以1为开头的所有排列后面出现的,然后X加上以1为开头的所有排列数,即加上1 *2!(因为后面还剩2位数)。
第二位数是3,比3小且前面没有出现的数有:1,说明231是在以23为开头的所有排列后面出现的,然后X加上以23为开头的全排列的排列数,即加上1 *1!(同上)。
第三位数是1,没有比3小且前面没有出现的数,说明并不是所有以231为开头的排列都在231后面,所以不需要加。
以上算出的X是比231小的排列数,但是结果要求的是231的顺序,所以要在X上再加上1。

换一个栗子:n=5,要求的排列为32415
第一个数是3,比3小且前面没有出现的数有:1,2,说明32415是在以1和2为开头的所有排列后面出现的,所以X要加上以1和2为开头的所有排列数,即加上1 *4!+1 *4!=2 *4!=48(因为后面还剩4位数,所以要乘上4的全排列即4!)。
第二位数是2,比2小且前面没有出现的数有:1,说明32415是在以31为开头的所有排列后面出现的,然后X加上以31为开头的全排列的排列数,即加上1 *3!=6(同上)。
第三位数是4,比4小且前面没有出现的数有:1,说明32415是在以321为开头的所有排列后面出现的,然后X加上以321为开头的全排列的排列数,即加上1 *2!=2(同上)。
第四位数是1,没有比1小且前面没有出现的数,所以并不是所有以32415为开头的排列在32415前面出现过,所以不需要加。
第五位数是5&

  • 16
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值