本人在比赛中经常会忘记怎么写乘法逆元,故此写下这篇笔记,方便自己和其他人查阅。
定义
如果 $ax \equiv 1 \pmod{p}$,则称 $x$ 为 $a$ 在模 $p$ 意义下的乘法逆元,记作 $a^{-1}$。
逆元的存在性条件是 $a$ 和 $p$ 互质,既 $\gcd(a,p)= 1$。
用处
乘法逆元在模 $p$ 意义下的除法中起到关键作用。对于 $a$ 和 $b$,如果我们想计算 $\frac{a}{b} \mod p$,可以转化为 $a \cdot b^{-1} \mod p$。
求法
扩展欧几里得算法
扩展欧几里得算法可以用来求解 $ax + by = \gcd(a, b)$ 的整数解。对于模 $p$ 的情况,我们可以设 $b = p$,则有:
$$ax + py = \gcd(a, p)$$
根据逆元的存在条件可知 $\gcd(a, p) = 1$,则有:
$$ax + py = 1$$
从而 $x$ 就是 $a$ 在模 $p$ 意义下的乘法逆元。
代码实现
1 | void exgcd(int a, int b, int &x, int &y) |
快速幂
如果 $p$ 是质数,可以使用快速幂来求逆元。根据费马小定理,对于质数 $p$,有:
$$a^{p-1} \equiv 1 \pmod{p}$$
因此:
$$a^{p-2} \equiv a^{-1} \pmod{p}$$
所以可以通过快速幂计算 $a^{p-2} \mod p$ 来得到 $a$ 的逆元。
代码实现
1 | int modInverse(int a, int p) |
注意: 快速幂法使用了 费马小定理,要求 $p$ 是质数,如果 $p$ 不是质数,则需要使用扩展欧几里得算法。
预处理逆元
如果需要频繁计算多个数的逆元,可以预处理所有数的逆元。可以使用一个数组 inv
,其中 inv[i]
存储 $i$ 在模 $p$ 意义下的逆元。
递推关系为:
$$inv[i] = (p - p / i) \cdot inv[p \mod i] \mod p$$
代码实现
1 | const int MAXN = 1000000; // 根据需要调整大小 |