Loading

CM 2-2 学习文章

置换介绍

定义:\(p_1, \cdots, p_n\)\(1 - n\) 的排列,则 \(\pi = \begin{pmatrix} 1 & 2 & \cdots & n \\ p_1 & p_2 & \cdots & p_n\end{pmatrix}\) 是一个置换。置换是一个排列到排列的一一映射(\(i \rightarrow p_i\))。

\(e = \begin{pmatrix}1 & 2 & \cdots & n \\ 1 & 2 & \cdots & n\end{pmatrix}\) 是一个单位元。

置换的乘法和函数的复合本质一样。

置换的逆元定义与数论逆元相似,都是 \(p \times p^{-1} = e\)

置换满足封闭性,置换的乘法满足结合律。

如果有一个置换 \((c_1, c_2, \cdots, c_k)\),且 \(c_1 \rightarrow c_2, c_2 \rightarrow c_3, \cdots, c_k \rightarrow c_1\),那么这个置换就是轮换。

因此,容易发现一个置换能被唯一分解成若干个轮换。这种分解被称为轮换分解。

置换可以分为两种类型:奇置换和偶置换。其中,偶置换是指置换的逆序对个数为偶数的置换,奇置换相反。

一个小结论:一个置换乘上一个对换,它的奇偶性会改变。

对于置换,还有一种分类方法。我们考虑置换的每个轮换分解的大小构成的集合。我们称 \(\Pi_{i = 1}^n i^{c_i}\) 类置换是有 \(c_i\) 个大小为 \(i\) 的轮换。

Cauchy 公式

Cauchy 公式:有 \(\frac{n!}{\prod_{i=1}^n c_i! \times \prod_{i = 1}^n i^{c_i}}\) 个类型为 \(\prod_{i = 1}^n i^{c_i}\) 的置换。

以下为感性计算。

我们先考虑每个轮换内的情况。显然,假设有一个大小为 \(x\) 的轮换,则与他相等的轮换还有 \(x - 1\) 个,总共 \(x\) 个。因此,我们应当将答案乘上 \(\frac{1}{x}\)

我们再考虑相同大小的轮换。我们发现,这些轮换可能通过轮换之间的排列得到与原来一致的置换,因此,我们应当将答案乘上 \(\frac{1}{c_i!}\)

综上,答案为 \(\frac{n!}{\prod_{i=1}^n c_i! \times \prod_{i = 1}^n i^{c_i}}\)

例一 CF612E Square Root of Permutation

简要题意:给定置换 \(p\),构造置换 \(q\) 使得 \(q^2 = p\)

我们考虑对于每一个轮换 \(t\),它的平方是什么样的。假设 \(t\) 的长度为奇数,容易发现 \(t ^ 2\) 的长度还是和原来相等。而如果 \(t\) 的长度为偶数,则 \(t^2\) 是两个大小相等的轮换。因此,我们算出 \(p\) 的各个轮换。对于相等偶数长度的轮换,两两匹配,奇数长的的轮换调整顺序即可。如果不能被分配完就是无解。

例二 P4161 游戏

简要题意:有多少种不同的长度为 \(n\) 的置换的阶,其中 $ n \leq 1000$。

假设对于一个置换 \(p\),它的轮换分解中轮换的大小为 \(c_1, \cdots, c_k\),显然该置换的阶是 \(\text{lcm}\{c_1, \cdots, c_k\}\)。那么问题转化为当 \(\sum_{i = 1}^n c_i = n\) 时,\(\text{lcm}\{c_1, \cdots, c_k\}\) 的不同种数。

发现由于 \(\text{lcm}\) 太大不好做,而且不同种数似乎并不好计算,于是自然地想到找到一个一一映射。容易发现可以加一个限制条件,就是 \(c\) 两两互素。

如果有 \((dk_1, dk_2) = d\),其中 \(d > 1\),可以被 \(dk_1, k_2, 1, 1, \cdots, 1\) 等效替代。

同理,可以再加一个限制条件:每个 \(c_i\) 必是 \(1\) 或者 \(p_{x}\),其中 \(p\) 为素数。

如果有 \(c_i = p^xy\),可以拆成 \(p^x, y, 1, \cdots, 1\)

容易发现,如果我们强制 \(c_i\) 有序,则此时的 \(c_i\) 个数与 \(\text{lcm}\) 个数一一映射。

如果我们把 \(1\) 去掉,则问题变成 \(c_i = p_i^x\)\(p_i\) 单调递增,\(\sum_{i = 1}^n c_i \leq n\) 的个数有多少。简单线性 dp 可以做到。

void solve() {
    n = read();
    Eular(n);
    dp[0][0] = 1;
    for (int i = 1; i <= tot; i ++) {
        for (int j = 0; j <= n; j ++) {
            dp[i][j] = dp[i - 1][j];
            for (int k = 1, now = pr[i]; now <= j; k ++, now *= pr[i])
                dp[i][j] += dp[i - 1][j - now];
        }
    }
    long long ans = 0;
    for (int j = 0; j <= n; j ++)
        ans += dp[tot][j];
    cout << ans << '\n';
}
posted @ 2025-02-12 19:08  DE_aemmprty  阅读(59)  评论(2)    收藏  举报