【模板】康托展开

已知一个$1—n$的排列$A=\{a_1,a_2,\cdots,a_n\}$,求它在所有排列中的字典序排名。

常用于将$n$个全排列映射到$n!$个自然数中。

 

求解这个问题的思路大概是下面这样的:

$(1)$ $A$的排名=字典序小于$A$的排列个数。所以只需要知道有多少个排列比$A$小就好了w

$(2)$ 我们按位考虑,第一位小于$a_1$的所有排列肯定比$A$小,这部分有$(a_{1}-1)\times (n-1)!$个。

$(3)$ 在第一个数等于$a_1$的所有排列中,第二位小于$a_2$的所有排列也肯定比$A$小。

    那么这部分有$(a_{2}-1)\times (n-2)!$个对不对?

    但是这个时候出现了一个问题:

    如果$a_{1}<a_{2}$,那么第二位就不能再用$a_1$这个数了(因为是排列)。

    所以应该有$(a_{2}-2)\times (n-2)!$个。

    当然如果$a_{1}>a_{2}$就不需要额外$-1$了w

$(4)$ 现在我们把$(3)$的结论推广,

    前$i-1$位与$A$相同且第$i$位小于$A$的排列,共有$(a_{i}-cnt_{i}-1)\times (n-i)!$个。

    其中$cnt_i$表示$\{a_{1},a_{2},\cdots ,a_{i-1}\}$中小于$a_i$的个数。

    显然所有这样的排列加起来就是比$A$小的排列总数(有序统计)。

$(5)$ 注意到$a_{i}-cnt_{i}-1$还等于后$\{a_{i},a_{i+1},\cdots ,a_{n}\}$中小于$a_i$的个数(因为是排列……)。

    所以我们就得到了康托展开公式:

    $Rank_{A}=b_{n}\times (n-1)!+b_{n-1}\times (n-2)!+\cdots +b_1 \times 0!$

    其中$b_{i}$表示$a_i$在当前未出现的$a$中排在第几个。

 

关于实现,只需要按定义模拟即可。

代码:

inline int Cantor(){ int rank=0; for(int i=1;i<=N;i++){ int s=0; for(int j=i+1;j<=N;j++) s+=(A[j]<A[i]); rank+=s*jc[N-i]; } return rank; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygzfw.html