乘法逆元

· · 算法·理论

乘法逆元的定义

乘法逆元是一个数 b,对于一个整数 a,满足以下公式:

a×b \equiv 1\ (\bmod\ m)

ab 的乘积对 m 取余后等于 1。只有当 am 互质(\gcd⁡(a,m)=1),乘法逆元才存在。

费马小定理

适用条件:模数 m 必须是素数,且 am 互质。

公式推导 费马小定理告诉我们,如果 m 是素数且 am 互质,则:

a^{m-1} \equiv 1 \ (\bmod\ m)

将两边同时除以 a ,得到:

a^{m-2} \equiv a^{-1} \ (\bmod\ m)

因此,乘法逆元 a^{-1}\ (\bmod \ m) 可以用以下公式计算:

a^{-1} \equiv a^{m-2} \ (\bmod\ m)

例子:求 3 在模 7 下的逆元

模数 m=7,且 m 是质数,使用公式 a^{m-2} \bmod\ m

3^{-1} \equiv 3^{7-2} \equiv 3^5\ (\bmod\ 7)

直接计算 3^5 \bmod 7 = 5

逐步计算 3^5 \bmod 7

  1. 3^2 = 9 \equiv 2\ (\bmod\ 7)
  2. 3^4 = (3^2)^2 = 2^2 = 4\ (\bmod\ 7)
  3. 3^5 = 3^4 \times 3 = 4 \times 3 = 12 \equiv 5\ (\bmod\ 7)
## 扩展欧几里得 **适用条件**:只要 $a$ 和 $m$ 互质即可,无需 $m$ 是素数。 ### **基本原理** 扩展欧几里得算法不仅能求最大公约数,还能找到整数 $x$ 和 $y$ 使得: $$$ax+my=\gcd(a, m)$$$ 当 $\gcd(a,m)=1$ 时,方程变为: $$$ax+my=1$$$ 将方程两边对 $m$ 取模,那么 $my$ 对 $m$ 取模即 $0$,得到: $$$ax \equiv 1\ (\bmod\ m)$$$ 这表明 $x$ 就是 $a$ 的乘法逆元。 ### 步骤 **1. 普通欧几里得算法:求最大公约数(GCD)** 我们先通过普通的欧几里得算法(辗转相除法)求出两个数的最大公约数。假设我们有两个整数 $a$ 和 $b$,我们通过以下递归步骤来计算它们的 GCD: 1. $a=b \times q_1+r_1
  1. b=r_1\times q_2+r_2
  2. r_1=r_2\times q_3+r_3
  3. ······
  4. r_{n-2} = r_{n-1} \times q_n + r_n
  5. 最终直到某一余数为零为止,最后一个非零余数就是 \gcd(1,b)

2.\ 反向推导:扩展过程

在计算 \gcd(a,m) 的过程中,我们逐步记录每一次除法的余数和商。然后通过反向推导的方式,得到整数 xy,使得:

ax+my=\gcd(a, m)

\gcd(a,m) = 1 的情况下,x 就是 a 对模 m 的乘法逆元。

例子:求 3 在模 11 下的逆元

  1. 用普通欧几里得算法(辗转相处法)求 \gcd(3,11)

    · 11 = 3 \times 3 + 211 \div 3 = 3 \cdots 2

    · 3 = 2 \times 1 + 13 \div 2 = 1 \cdots 1

    · 2 = 2 \times 1 + 02 \div 1 = 2 \cdots 0

    最后 \gcd(3,11) = 1,表示 311 互质,所以乘法逆元存在。

  2. 反向推导(扩展欧几里得算法):

从第二步(3 = 2 \times 1 + 1)反向推导,计算 xy

从第二步 3 = 2 \times 1 + 1 得到:

1 = 3 - 2 \times 1

然后,将第一步中的 2 = 111-3\times3 带入上式:

1 = 3 - 1 \times (11 - 3 \times 3) 1 = 3 - 1 \times 11 + 3 \times 3 1 = 4 \times 3 - 1 \times 11

因此得到:

3 \times 4 + 11 \times (-1) = 1 ## 乘法逆元的作用 这里列举两个常用的作用。 ### 求解模线性同余方程 乘法逆元可以用来求解模线性同余方程: $$$ax \equiv b \ (\bmod\ m)$$$ 当 $a$ 和 $m$ 互质时,方程有唯一解,解法是通过计算 $a$ 在模 $m$ 下的逆元 $a^{-1} x \equiv b \sdot a^{-1}\ (\bmod\ m)

示例:

求解3x \equiv 7\ (\bmod\ 11)

  1. 先求 3\bmod\ 11 下的逆元,3^{-1} \equiv 4\ (\bmod\ m)
  2. 解方程:x \equiv 7\sdot 4 \equiv 28 \equiv 6\ (\bmod\ 11)
\therefore x=6

计算分数的模运算

在整数模运算中,分数无法直接处理。例如,计算 \frac{a}{b}\ (\bmod\ m) 时,可以通过乘法逆元将其转化为:

\frac a b \equiv a\sdot b^{-1}\ (\bmod\ m) ## 代码 ### 费马小定理 + 快速幂 ```cpp int qpow(int x, int y) { int res = 1; for(; y > 0; x = (x * x) % mod, y >>= 1) if(y & 1) res = (res * x) % mod; return res; } int inv(int a) {return qpow(a, mod - 2);} ``` ### 扩展欧几里得 ```cpp int exgcd(int a, int b, int &x, int &y) { if(b == 0) {x = 1; y = 0; return a;} int d = exgcd(b, a % b, y, x); y -= a / b * x; return d; } int inv(int a) { int x, y; exgcd(a, mod, x, y); return (x + mod) % mod; } ``` ### 线性求 $\bold{1-n}$ 逆元 ```cpp void init(int m) { inv[1] = 1; for(int i = 2; i <= m; ++i) inv[i] = (mod - mod / i) * inv[mod % i] % mod; } ``` ### 线性求 $\bold{1-n}$ 逆元(妙招) ```cpp void init(int m) { fac[0] = 1; for(int i = 1; i <= m; ++i) fac[i] = (fac[i - 1] * i) % mod; fac_inv[m] = qpow(fac[m], mod - 2); for(int i = m; i >= 1; --i) fac_inv[i - 1] = (fac_inv[i] * i) % mod; for(int i = 1; i <= m; ++i) inv[i] = (fac_inv[i] * fac[i - 1]) % mod; } ``` ### 线性求 $\bold{\text{val}_1,\text{val}_2,...,\text{val}_n}$ 逆元 ```cpp void init(int m) { fac[0] = 1; for(int i = 1; i <= m; ++i) fac[i] = (fac[i - 1] * val[i]) % mod; fac_inv[m] = qpow(fac[m], mod - 2); for(int i = m; i >= 1; --i) fac_inv[i - 1] = (fac_inv[i] * val[i]) % mod; for(int i = 1; i <= m; ++i) inv[i] = (fac_inv[i] * fac[i - 1]) % mod; } ``` ## 总结 - 费马小定理:适合模数 $m$ 是素数时使用,直接计算 $a^{m-2} \bmod m$。 - 扩展欧几里得算法:通用方法,无论模数是否是素数,只要 $a$ 和 $m$ 互质,都可以用。 - OI Wiki: https://oi-wiki.org/math/number-theory/inverse/