乘法逆元=>学习笔记

前言

在讲 中国剩余定理 的时候,没有系统性的讲一遍乘法逆元,所以有了这一期专栏。

定义

如果有一个线性同余方程 \(ax\equiv1\pmod{p}\),则称 \(x\)\(a\equiv p\) 的乘法逆元。记作 \(a^{-1}\)

但是,只有当 \(\gcd(a,p)=1\) 时,乘法逆元才存在。

求乘法逆元

费马小定理

如果 \(\gcd(a,p)=1\),那么 \(a^{p-1}\equiv1\pmod{p}\)

经过计算,得:\(a\times a^{p-2} \equiv 1 \pmod p\)

所以,在 \(\gcd(a,p)=1\) 时,\(a^{p-2}\) 就是 \(a\) 的乘法逆元。

这个情况在 C++ 可以用快速幂进行求解。

扩展欧几里得(exgcd)

exgcd 用来求 \(ax+by = \gcd(a,b)\) 的解。

在求解过程中我们需要分类讨论。

\(b=0\) 时,化简得 \(ax = \gcd(a,0)\),因为 \(\gcd(a,0)=a\),所以 \(ax = a\),解得 \(x=1\)

此时,\(y\) 有无数组解,我们不妨设 \(y=0\)

\(b \ne 0\) 时,\(\gcd(a,b) = \gcd(b, a \bmod b)\)(欧几里得算法)

于是 \(ax+by=\gcd(b, a \bmod b)\)

此时可以看做 \(a\) 对应 \(b\)\(b\) 对应 \(a \bmod b\),不是相等

所以左边等于 \(bx+(a \bmod b) y\)

假设有一组解

\(\begin{cases} x = x_0 \\ y = y_0 \\ \end{cases}\)

使得原方程组成立。

又因为 \(a \bmod b = a - \left \lfloor \frac{a}{b} \right \rfloor b\)

所以左边等于

\[\begin{aligned} bx_0+(a - \left \lfloor \frac{a}{b} \right \rfloor b)y_0 \\ =bx_0+ay_0-\left \lfloor \frac{a}{b} \right \rfloor by_0 \\ =ay_0+b(x_0-\left \lfloor \frac{a}{b} \right \rfloor y_0) \end{aligned}\]

所以 \(ax_0+by_0 = ay_0+b(x_0-\left \lfloor \frac{a}{b} \right \rfloor y_0)\)

所以

\(\begin{cases} x_0 = y_0 \\ y_0 = x_0-\left \lfloor \frac{a}{b} \right \rfloor y_0 \\ \end{cases}\)

这就是推导过程,在 C++ 中,我们可以采用递归的思想进行求解。

\(x\) 就是我们要求的乘法逆元,而 \(ax \equiv 1 \pmod p\),可以看做 \(ax \bmod p = 1\),令 \(p = by\),则 \(ax + by = \gcd(a,p)\),又因为乘法逆元存在的条件为 \(\gcd(a,p)=1\),所以 \(ax+by=1\)。此时,用 exgcd 求 \(x\)

void exgcd(ll a, ll b, ll &x, ll &y) {
	if (!b) { // b=0 的情况
		x = 1, y = 0;
		return ;
	}
	exgcd(b, a % b, y, x); // 注意这里 y 和 x 交换一下
	y = y - (a / b) * y; // 这里的第二个 y 可以看做 x
}

注意,\(x\) 可能最终是负数,所以算出来最后要先模 \(p\),再加 \(p\),再模 \(p\)

x = (x % p + p) % p;

递推法求乘法逆元

这一点非常的重要!

应用:求 \(1 \sim n\) 的所有乘法逆元。

时间复杂度:\(O(n)\)

首先,我们要知道 \(1^{-1} \equiv 1 \pmod p\),因为:显然,在 \(p\) 下,\(1\)\(1\) 的乘法逆元。

其次,对于递归情况 \(i^{-1}\),我们设 \(k=\left \lfloor \frac{p}{i} \right \rfloor, j = p \bmod i\),则有 \(p = ki + j\)

所以,在模 \(p\) 意义下,\(ki+j \equiv 0 \pmod p\)

此时,左右两边同时乘以 \(i^{-1} \times j^{-1}\),得:

\[ki \times i^{-1} \times j^{-1} + j \times i^{-1} \times j^{-1} \equiv 0 \pmod p \]

\[kj^{-1}+i^{-1} \equiv 0 \pmod p \]

\[i^-1 \equiv -kj^{-1} \pmod p \]

再带入 \(j = p \bmod i, k = \left \lfloor \frac{p}{i} \right \rfloor\),得:

\[i^{-1} \equiv -\left \lfloor \frac{p}{i} \right \rfloor (p \bmod i)^{-1} \pmod p \]

注意, \(p \bmod i < i\),又因为在递推的过程中,我们已经求出了所有小于 \(i\) 的在模 \(p\) 意义下的乘法逆元,可表示为 \(q^{-1}, q<i\)

所以就有递推式:

\(inv[i] \equiv \begin{cases} 1 \,\,\,\,\,\,\,(i=1) \\ -\left \lfloor \frac{p}{i} \right \rfloor inv[p \bmod i] \,\,\,\,\,\,\, (i \ne 1, i > 1)\\ \end{cases} \pmod p\)

这也可以用 C++ 的代码来表示:

for (int i = 1; i <= n; i++) {
		if (i == 1) inv[i] = 1;
		else inv[i] = (long long)(p - p / i) * inv[p % i] % p;
		// p - p / i 避免出现负数 
}

结束语

到这里就结束啦!

posted @ 2025-03-20 12:08  Panda_LYL  阅读(39)  评论(0)    收藏  举报