康托展开学习笔记

摘自OI Wiki
康托展开可以用来求一个 1 ∼ n 1 \sim n 1n的任意排列的排名

排列的排名: 1 ∼ n 1 \sim n 1n的所有排列按字典序排序,这个排列的位次就是它的排名

时间复杂度

康托展开可以在 O ( n 2 ) O(n^2) O(n2)的复杂度内求出一个排列的排名,在用到树状数组优化时可以做到 O ( n l o g n ) O(n log n) O(nlogn)

实现

因为排列都是按照字典序排名的,因此越靠前的数字优先级越高。也就是说如果两个排列的某一位之前的数字都是相同的,那么如果这一位不相同,就按这一位排序,

比如 4 4 4的排列, [ 2 , 3 , 1 , 4 ] < [ 2 , 3 , 4 , 1 ] [2,3,1,4]<[2,3,4,1] [2,3,1,4]<[2,3,4,1],因为在第三位出现不同,则 [ 2 , 3 , 1 , 4 ] [2,3,1,4] [2,3,1,4]的排名在 [ 2 , 3 , 4 , 1 ] [2,3,4,1] [2,3,4,1]的前面.

栗子

我们知道常为 5 5 5的排列 [ 2 , 5 , 3 , 4 , 1 ] [2,5,3,4,1] [2,5,3,4,1]大于以 1 1 1为第一位的任何排列,以 1 1 1为第一位的 5 5 5的排列有 4 ! 4! 4!种。这是非常好理解的。但是我们对第二位的 5 5 5而言,它大于第一位与这个排列相同的,而这一位比 5 5 5小的所有排列。不过我们需要注意的是,这一位不仅要比 5 5 5小,而且还要满足没有在当前排列的前面出现过,不然就统计重复了。因此这一位为 1 , 3 1,3 13 4 4 4,第一位为 2 2 2的所有排列都比它要小,数量为 3 × 3 ! 3 \times 3 ! 3×3!

按照这样统计下去,答案就是 1 + 4 ! + 3 × 3 ! + 2 ! + 1 = 46 1+4!+3\times 3!+2!+1=46 1+4!+3×3!+2!+1=46

小解析:

  1. 1 1 1为第一位的 5 5 5的排列有 4 ! 4! 4!

  2. 第二位小于 5 5 5且在前面没有出现过的有三个数 ( 1 , 3 , 4 ) (1,3,4) (1,3,4),即第二位上是 1 , 3 , 4 1,3,4 1,3,4的情况都合理。 3 , 4 , 5 3,4,5 3,4,5的排列情况总共 3 ! 3! 3!种,根据乘法原理满足情况的 3 × 3 ! 3\times 3! 3×3

  3. 第三位小于 3 3 3且在前面没有出现过的数只有 1 1 1 2. 2. 2.同理,共 1 × 2 ! 1\times 2! 1×2!

  4. 第四位小于 4 4 4且没在前面出现过的只有 1 1 1,共 1 × 1 ! = 1 1\times 1!=1 1×1!=1

  5. 最前面的 + 1 +1 +1是因为求排名,加上了自身

注意:

我们每次要用到当前有多少个小于它的数还没有出现,这里用树状数组统计比他小的数出现过的次数就行

逆康托展开

因为排列的排名和排列是一一对应的,所以康托展开满足双射关系,是可逆的。可以通过类似上面的过程倒推回来。

如果我们知道一个排列的排名,就可以推出这个排列,因为 4 ! 4! 4!是严格大于 3 × 3 ! + 2 × 2 ! + 1 × 1 ! 3\times3!+2\times2!+1\times1! 3×3!+2×2!+1×1!(可利用反正法求解)的,所以可以认为对于长度为 5 5 5的排列,排名 x x x除以 4 ! 4! 4!向下取整就是有多少个数小于这个排列的第一位。

小解析:

长度为 5 5 5的排列的最大排名为 4 × 4 ! + 3 × 3 ! + 2 × 2 ! + 1 × 1 ! 4\times4!+3\times3!+2\times2!+1\times1! 4×4!+3×3!+2×2!+1×1!

前面的系数为小于当前的数且前面没有出现过的数的个数

所以除以 4 ! 4! 4!下取整时 3 × 3 ! + 2 × 2 ! + 1 × 1 ! 3\times3!+2\times2!+1\times1! 3×3!+2×2!+1×1!不会对要求的数( 4 ! 4! 4!的系数)产生影响

栗子(同上一个

首先让 46 − 1 = 45 46-1=45 461=45 45 45 45代表着有多少个排列比这个排列小。

⌊ 45 4 ! ⌋ = 1 \left\lfloor\frac{45}{4!}\right\rfloor= 1 4!45=1,有一个数小于它,所以第一位是2

此时让排名减去 1 × 4 ! 1\times4! 1×4!得到 21 21 21 ⌊ 21 3 ! ⌋ = 3 \left\lfloor\frac{21}{3!}\right\rfloor=3 3!21=3有三个数小于它,去掉已经存在的2,这一位是 5 5 5

21 − 3 × 3 ! = 3 21-3\times3!=3 213×3!=3, ⌊ 3 2 ! ⌋ = 1 \left\lfloor\frac{3}{2!}\right\rfloor=1 2!3=1有一个数小于它,那么这一位就是 3 3 3

3 − 1 × 2 ! = 1 3-1\times2!=1 31×2!=1,有一个数小于它,这一位是剩下来的第二位:4,剩下一位就是 1 1 1

[ 2 , 5 , 3 , 4 , 1 ] [2,5,3,4,1] [2,5,3,4,1]

实际上我们得到了形如有两个数小于它这一结论,就知道它是当前第三个没有被选上的数,这里也可以用线段树维护,时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值