仍想起曾经自己在网上查阅算法时的崩溃,今天来重新学习这个算法时,感觉释然了许多…
康托展开常用来求解这样一个问题:
给定一个序列a包含 1~n ,求这个序列在 1~n 的全排列中,按字典序排第几个。
说枯燥点儿,它就是这个式子:
a n s = b n ( n − 1 ) ! + b n − 1 ( n − 2 ) ! + . . . + b 1 0 ! ans=b_n(n-1)!+b_{n-1}(n-2)!+...+b_1 0! ans=bn(n−1)!+bn−1(n−2)!+...+b10!
其中 b i b_i bi 表示其右边比 a i a_i ai 小的数的个数。
怎么去理解这个式子呢?举个例子:
求序列{3,4,1,2,5}关于原问题的答案
在这里只给出3,4的解释。
1.对于3,其右边有两个数1,2比之小,说明1,2作第一位的已经跳过了,然后因为第一位后面有4位,4位的全排列为4!,因此贡献为
2
×
4
!
2\times4!
2×4!
2.对于4,其右边同样有两个数1,2比之小,说明1,2作第二位的已经跳过了,然后因为第二位后面有3位,3位的全排列为3!,因此贡献为
2
×
3
!
2\times3!
2×3!
以此类推后,发现答案为60,可正确答案为61。
那么为什么要加一呢?
可以发现序列{1,2,3,4,5}答案为0。
因为康托展开的式子是以0开头的,但是正常计算需要+1 很少听到第0个序列的说法
类似这样一个问题:
给定一个序列a在 1~n 的全排列中按字典序排第几个,求这个序列
实质就是康托倒着问
所以我们倒着做
我们先将给出的字典序减1,然后列出后缀积
1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|
120 | 24 | 6 | 2 | 1 | 1 |
5! | 4! | 3! | 2! | 1! | 0! |
拿61举例子:
61 - 1 = 60
60 / 4! = 2 ……12 在{1,2,3,4,5}有2个比它小 即3
12 / 3! = 2 …… 0 在{1,2,4,5}有2个比它小 即4
0 / 2! = 0 …… 0 在{1,2,5}有0个比它小 即1
0 / 1! = 0 …… 0 在{2,5}有0个比它小 即2
0 / 0! = 0 …… 0 在{5}有0个比它小 即5
所以编号为61的答案序列为{3,4,1,2,5}