Loading

【专题】线性判定排列逆序数的奇偶性

排列逆序数的奇偶性是一个十分常见的属性。不同于直接求逆序数,由于排列的性质,这玩意是可以 \(\mathcal O(n)\) 直接求解的。为了完成这一点,引入如下基本结论:

  1. 排列两元素对换,逆序数奇偶性改变。
  2. 排列的逆序数同余 \(n - \#\)环。

第一点,在大多数线性代数教材中都有所提及。

第二点中的 “环” 的构造方式:按下标 \(i\)\(p_i\) 连边,或者说,两排列之间连边,必形成若干环(这是因为每个数都出现一次,对应的入/出度数为 \(1\))。

定义排列的复合 \((f \circ g)_x\)\(x\) 变为 \(f_{g_{x}}\),下证

\[\operatorname{parity}(f \circ g) = \operatorname{parity}(f) + \operatorname{parity}(g) \]

\(f\) 经过 \(\operatorname{swap}(i, j)\) 后,变为 \(f'\),其奇偶性变为 \(\operatorname{parity}(f) + 1\)。可表示为 \(f \circ g = f'\),其中排列 \(f, g\) 仅有 \((i, j)\) 两点顺序不同。这过程可以归纳,得到上述结论不难。

为啥是这个数[1]?考虑 \(\operatorname{swap}(i, j)\) 在从 \(i\)\(p_i\) 的图上是什么含义?注意到如果交换环上两点,将会产生一个自环,环的大小会减一。用上面的话来说,对于环 \(c_i \in \{C\}_k\)\(\operatorname{swap}(i, j)\) 实为 \(f \circ c_1 \circ c_2 \circ \cdots \circ c_k\),而在这个环上的奇偶变化为 \(k - 1\),将所有环的贡献相加就得到:

\[k_1 - 1 + k_2 - 1 + \cdots + k_t - 1 = n - \# 环 \]


这个结论十分有用。

有点记不清了但至少 ABC 出过三四次了,每次看蒋老师代码都觉得“哦,这tm我学过啊”真是十分常见的结论。下附代码:

bool parity = n & 1;
for (int i : p) if (~i) {
    for (int j = i; ~j; ) {
        std::tie(j, p[j]) = std::tuple{p[j], -1};
    }
    parity ^= 1;
}

  1. 参考 CodeForces Blog: https://codeforces.com/blog/entry/97849 ↩︎

posted @ 2023-04-03 21:32  PatrickyTau  阅读(584)  评论(0编辑  收藏  举报