康托展开

一些定义

有一个长度为 \(n\) 的排列 \(P\)

定义排列通过字典序比大小,即若长度为 \(n\) 的排列 \(A,B\)

  • 任意 \(1\le j<i\le n,A_j=B_j\)
  • \(A_i<B_i\)

则有排列 \(A<B\)。这里不考虑长度不一样的情况。

定义一个排列 \(P\) 的排名 \(rnk(P)\) 为比它小的排列数量 \(+1\)

康托展开

给定 \(P\),求 \(rnk(P)\)

等价于:求长度为 \(n\) 的排列 \(Q\),满足 \(Q<P\) 的数量(\(+1\))。

考虑枚举定义中的 \(i\)。于是 \(\forall 1\le j<i\le n,Q_j=P_j\)。那么 \(Q_i\) 可以是哪些数呢?

  • \(Q_i<P_i\implies Q_i\ne P_i\implies i\ne k\)
  • \(Q_i\ne Q_j\iff \exist k,i\le k,Q_i=P_k\)

\(\implies\exist k,i<k,Q_i=P_k<P_i\),故 \(Q_i\) 的取值数量(记为 \(f(i)\))即为

\[f(i)=\sum_{k=i+1}^{n}[P_k<P_i] \]

其中 \([X]\) 表示条件 \(X\) 是真(\(1\))/假(\(0\))。

这是典型的二维偏序问题。可以用树状数组实现。

求出了 \(Q_i\) 取值数量,考虑求 \(Q_{i+1}\sim Q_n\) 的排列数量。

由于已经满足 \(Q_i<P_i\),故后面 \((n-i)\) 个数可以随便排列,排列数量为 \((n-i)!\)。故在 \(i\) 处小于 \(P\) 的排列数量为

\[(n-i)!\times f(i) \]

将所有 \(i\) 的贡献相加,即可得到

\[rnk(P)=1+\sum_{i=1}^{n}(n-i)!\times f(i) \]

倒序枚举 \(i\)\(f(i)\) 可以使用树状数组在 \(O(\log n)\) 时间计算,故该算法可以在 \(O(n\log n)\) 时间内计算某个排列的排名,被称为康托展开

逆康托展开

排名可以逆推得到排列。

但可以发现有 \(n=20\) 时,全排列数量 \(n!=2432902008176640000>10^{18}\)

所以,若题目给的排名 \(rnk(P)\le 10^{18}\)(不需要高精),有 \(n=|P|\le 20\)

于是,我们可以完成如下 \(n\) 次操作:

  • \(r_0=rnk(P)-1\),集合 \(S=\{1,2,\cdots,n\}\)
  • 对于第 \(j\) 次操作,\(r_j\gets r_{j-1}\bmod (n-j)!\)\(k_j\gets\cfrac{r_{j-1}-r_j}{(n-j)!}\)
  • \(S\) 中取出第 \((k_j+1)\) 大的元素 \(x\),有 \(P_j=x\)。从 \(S\) 中删除 \(x\)
  • 重复进行上面两步 \(n\) 次。

解释一下:

每次操作从 \(r_{j-1}\) 中分离出 \(f(j)\),以 \(j=1\) 为例

\[r_0=\sum_{i=1}^{n}(n-i)!\times f(i)\\ \begin{aligned} r_1&\gets r_0\bmod (n-1)!\\ &=\left(\sum_{i=1}^{n}(n-i)!\times f(i)\right)\bmod (n-1)!\\ &=\sum_{i=1}^{n}\Big((n-i)!\times f(i)\bmod (n-1)!\Big)\\ &=\Big((n-1)!\times f(1)\bmod (n-1)!\Big)+\sum_{i=2}^{n}\Big((n-i)!\times f(i)\bmod (n-1)!\Big)\\ &=\sum_{i=2}^{n}\Big((n-i)!\times f(i)\bmod (n-1)!\Big) \end{aligned}\\ \begin{aligned} \because & f(i)=\sum_{k=i+1}^{n}[P_k<P_i]\le n-i<n-i+1\\ \therefore & (n-i)!\times f(i)<(n-i)!\times (n-i+1)=(n-i+1)!\le (n-1)!\\ \therefore & (n-i)!\times f(i)<(n-1)!\\ \therefore & (n-i)!\times f(i)\bmod (n-1)!=(n-i)!\times f(i)\\ \therefore & r_1\gets \sum_{i=2}^{n}\Big((n-i)!\times f(i)\bmod (n-1)!\Big)=\sum_{i=2}^{n}(n-i)!\times f(i) \end{aligned}\\ \]

有没有发现 \(r_1\)\(r_0\) 几乎一致(除了 sigma 下界从 \(1\) 变成 \(2\))?

对于 \(k_1\)

\[\begin{aligned} k_1&\gets\cfrac{r_0-r_1}{(n-1)!}\\ &=\cfrac{\sum_{i=1}^{n}(n-i)!\times f(i)-\sum_{i=2}^{n}(n-i)!\times f(i)}{(n-1)!}\\ &=\cfrac{(n-1)!\times f(1)}{(n-1)!}\\ &=f(1) \end{aligned} \]

如此这般,我们进行了完美的迭代,每次将 \(f(j)\) 分离,从 \(S\) 中找出合适的 \(x\)。然后将 \(r_{j-1}\)\(i=j\) 那项消去(simga 上界加 \(1\))。

形式化地说,我们的处理方式使得有 \(r_j,k_j\) 的通项公式

\[r_j=\sum_{i=j+1}^{n}(n-i)!\times f(i)\\ k_j=f(j) \]


\(S\) 可以用 vector 维护,复杂度 \(O(n^2)\)。因为 \(n\le 20\),复杂度足够。

若毒瘤出题人让 \(rnk(P)>10^{18}\),也不要紧。上线段树二分维护 \(S\) 即可。

posted @ 2024-06-02 17:36  Po7ed  阅读(2)  评论(0编辑  收藏  举报