【数论】分数取模 - 逆元

在 OI 中我们常常需要对答案取模。

对于输出为分数的题目,我们一般不愿意直接输出 double 造成浮点误差,输出 a/b 形式又过于麻烦,并且不支持取模。

所以对于分数,我们需要定义一种新的取模方法。

定义

我们从整数取模的定义对分数取模进行拓展,我们希望 \(\frac{a}{b} \bmod m\) 答案是一个整数。

整数取模中,\(a \equiv b \pmod m\) 的定义是 \(m~|~a-b\),同时对于任意整数 \(c\)\(ca \equiv cb \pmod m\)

于是同理对于分数取模 \(\frac{a}{b}\equiv c\pmod m\),我们应当尽量让其满足上面的公式,\(\frac{a}{b} b\equiv cb\pmod m\),也就是 \(a\equiv cb\pmod m\)

\(cb\bmod m\)\(c\in [0, m)\) 时会遍历 \((b,m)\) 的倍数,也就是说我们需要满足 \(a | (b, m)\)

这时让等式两边和模数同除 \((b, m)\),转化为 \((b, m) = 1\) 的情况。

也就是说,分数取模的问题可以强化为,对于 \((a, m) = 1\),找出一个 \(b\) 满足

\[ab \equiv 1 \pmod m \]

我们就可以说 \(b\)\(a\) 的逆元,也就是

\[a^{-1} \equiv b \pmod m \]

显然该 \(b\)\(\bmod m\) 条件下唯一。

计算

费马小定理

根据费马小定理,我们有一个十分简单的公式。

\[a^{\varphi(m)} \equiv 1 \pmod m \]

所以有

\[a^{\varphi(m)-1} \equiv a^{-1} \pmod m \]

\(m\) 为质数 \(p\) 时,因为 \(\varphi(p) = p-1\),特别的,有

\[a^{p-2} \equiv a^{-1} \pmod p \]

所以我们可以用快速幂 \(O(\log \varphi(m))\) 计算一个数的逆元。但对于非素数 \(m\),我们需要另一个方法计算 \(\varphi(m)\),或者使用扩展欧几里得。

扩展欧几里得

注意 \(ab \equiv 1 \pmod m\) 可以转化为,存在 \(k\) 使得

\[ab + km = 1 \]

这显然是欧几里得算法的形式。

我们可以通过扩展欧几里得解得 \(a\) 的值。

复杂的为欧几里得的复杂度 \(O(\log m)\)

多组逆元预处理

这是一个快速计算 \(n\) 个数逆元的技巧,这个技巧十分简单,但许多初学者并没有意识到。

对于计算一个序列 \(a_1, a_2, \dots, a_n\) 内所有数模 \(m\) 意义下的逆元,我们可以用 \(o(n + \log m)\) 的时间复杂的完成。

具体的,我们对序列 \(a\) 进行前缀乘法,\(s_i = \prod_{j=1}^i a_i\)

然后处理出 \(s_n\) 的逆元。也就是 \(f_n = \frac{1}{\prod_{j=1}^n a_i} = \prod_{j=1}^n \frac{1}{a_i}\)

这时候我们可以反过来从 \(n\)\(1\) 依次乘上 \(a_i\),计算得到 \(f_i = \prod_{j=1}^i \frac{1}{a_i}\)

最后前后相消,\(a_i\) 的逆元 \(a_i^{-1} = (\prod_{j=1}^i \frac{1}{a_i})(\prod_{j=1}^{i - 1} a_i) = f_is_{i-1}\)

posted on 2025-12-08 20:01  Evan_song  阅读(24)  评论(0)    收藏  举报