摘自OI Wiki
康托展开可以用来求一个
1
∼
n
1 \sim n
1∼n的任意排列的排名
排列的排名: 把 1 ∼ n 1 \sim n 1∼n的所有排列按字典序排序,这个排列的位次就是它的排名
时间复杂度
康托展开可以在 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 1,3或 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为第一位的 5 5 5的排列有 4 ! 4! 4!种
-
第二位小于 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且在前面没有出现过的数只有 1 1 1与 2. 2. 2.同理,共 1 × 2 ! 1\times 2! 1×2!种
-
第四位小于 4 4 4且没在前面出现过的只有 1 1 1,共 1 × 1 ! = 1 1\times 1!=1 1×1!=1种
-
最前面的 + 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 46−1=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 21−3×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 3−1×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)