【算法笔记】乘法逆元
- 本文总计约 8000 字,阅读大约需要 30 分钟。
- 警告!警告!警告!本文有大量的 \(\LaTeX\) 公式渲染,可能会导致加载异常缓慢!
前言
逆元可能是数论里面最最最最最重要的知识点了,因为大部分的 OI 题目里,都需要选手将答案对某个大质数(一般是 \(10^9+7\) 或者是 \(998244353\))取模,而在取模的过程中,因为取模不满足除法分配率,所以在遇见除法的时候,不能直接相除。
但这并不意味着我们对除法取模没有办法。而我们实现它的方法,就是使用乘法逆元来完成的。
题目引入
我们定义组合数 \(\dbinom{n}{m}\) 代表从 \(n\) 个互不相同的元素中,选择其中 \(m\) 个,有多少种选法。
计算组合数的公式为:\(\dbinom{n}{m}=\dfrac{n!}{m!\cdot (n-m)!}\),其中 \(n!\) 代表 \(n\) 的阶乘,它的定义为 \(n!=1\cdot 2\cdot\,\cdots\,\cdot n\)。
现在给你两个正整数 \(n,m\),且 \(n\ge m\),求 \(\dbinom{n}{m}\) 对 \(998244353\) 取模后的值。
暴力解法
对于求组合数问题,有两种基本的算法:
-
通过组合数公式 \(\dbinom{n}{m}=\dfrac{n!}{m!\cdot (n-m)!}\) 暴力硬算。
int不够开long long,long long不够写高精。复杂度为 \(\Theta(n)\)。然鹅如果 \(n\le 10^7\),写高精似乎会超时 QwQ。这也是为什么我们要让答案对 \(998244353\) 取模,根据同余定理,有 \((a\bmod c)(b\bmod c)=(ab)\bmod c\)。所以,无论 \(n\) 再怎么大,取模后的结果也总是能被一个
int变量存储下。大部分 OI 题里,答案对大数取模,目的就是让输出的答案不要过大毕竟写高精是很麻烦的一件事 QwQ。但是我们会发现,计算组合数的过程中,需要使用除法。这里要强调一下:\(\left(\dfrac{a}{b}\right) \bmod c\neq \left(\dfrac{a\bmod c}{b\bmod c}\right)\bmod c\)!例如,\(\dfrac{10}{2} \bmod 3=5\bmod 3=2\),但 \(\dfrac{10\bmod 3}{2\bmod 3}=\dfrac{1}{2}\),两者显然不相等。所以,我们不能直接对除法运算取模。
-
可以通过杨辉三角来计算组合数。根据公式 \(\dbinom{n}{m}=\dbinom{n-1}{m}+\dbinom{n-1}{m-1}\),我们可以存储先前已经算出来的组合数,然后递推地求出其它的组合数。
时间复杂度是 \(\Theta(n^2)\),比暴力硬算的效率低,却可以绕过除法取模的问题。但当 \(n\le 10^7\) 的时候,好像会超时 QwQ,所以我们只能放弃掉这个算法了。
乘法逆元
除法取模
正如上面所说,杨辉三角的算法时间复杂度太低,所以我们还是得回到 \(\Theta(n)\) 的公式爆算中来。既然如此,我们就必须得直面除法取模的算法。
我们考虑最简单的情况,即 \(\dfrac{a}{b}\) 对 \(c\) 取模:
我们在 \((1.1)\) 式两侧同时乘上一个 \(b\),那么上式变为:
现在,让我们再考虑这个同余方程:
假如我们能够解出方程 \((1.3)\) 中的 \(x\),再将其代入到 \((1.2)\) 中,就有了:
同时联立 \((1.1)(1.4)\),我们就可以得出:
也就是说,假如我们可以求出上面方程 \(3\) 中的 \(x\) 的值,我们就可以通过 \((1.5)\) 式求出 \(\dfrac{a}{b}\) 对 \(c\) 取模的结果了。
乘法逆元的概念
假如对于一个正整数 \(a\),存在一个整数 \(x\),使得同余方程 \(ax\equiv 1\pmod p\) 成立,那么我们称 \(x\) 为 \(a\) 在模 \(p\) 意义下的逆元,记做 \(x\equiv a^{-1}\pmod p\)。
它的作用是什么……当然就是向上面一样,解决除法取模的问题。因为除法是乘法的逆运算,我们就可以认为,在模 \(p\) 的意义下,除以一个整数,和乘以这个整数在模 \(p\) 意义下的逆元,效果是完全相同的。
乘法逆元的性质
我们对上面的乘法逆元的概念有了基本的了解,并且还可以通过观察,简单地得到一些乘法逆元的性质:
-
在模 \(p\) 意义下,任意一个数的乘法逆元一定小于 \(p\) 本身。
这个结论似乎很显然。因为我们不妨设 \(a\) 的乘法逆元为 \(x\),且 \(x>p\),那么一定有 \(a(x\bmod p)\equiv ax\equiv 1\pmod p\),所以 \((x\bmod p)\) 是 \(a\) 的乘法逆元,且 \((x\bmod p)<p\),所以 \(a\) 的乘法逆元小于 \(p\)。 -
在模 \(p\) 意义下整数 \(a\) 存在逆元,当且仅当 \(p\perp a\)。
不妨设 \(a^{-1}=x\),则:\[ax\equiv 1\pmod p.\qquad(2.1) \]稍微对 \((2.1)\) 做一下变形,就有:
\[ax=kp+1,k\in\mathbb{Z}.\qquad(2.2) \]移项,得:
\[ax+kp=1.\qquad(2.3) \]注意到这是一个关于 \(k,x\) 的二元一次不定方程。我们利用 Bézout 定理,可知,\(x\) 存在解,当且仅当 \(\gcd(a,p)=1\),即 \(a\perp p\),命题得证。
同时,我们也可以得到另外一个结论:在模 \(p\) 的意义下,\(1,2,\cdots,p-1\) 都存在逆元,当且仅当 \(p\) 是一个质数。
-
若 \(p\) 是质数,那么在模 \(p\) 意义下,\(1\) 的逆元为 \(1\),\((p-1)\) 的逆元为 \((p-1)\),除此以外,\(2\) 到 \((p-2)\) 之间,任何一个数和它的逆元一一对应。
这个结论又有一个高大上的名字,叫做 Wilson 定理:
当且仅当 \(p\) 是一个质数时,\((p-1)!\equiv -1\pmod p\)。
证明如下(数学证明警告!):
先证必要性,即 \((p-1)!\equiv-1\pmod p\Rightarrow\) \(p\) 是一个质数:
若 \(p\) 不是一个质数,存在正整数 \(a,b\) 使得 \(p=ab\),显然,\(a<p-1\),\(b<p-1\)。
当 \(a\neq b\) 时,\((p-1)!=1\cdot2\cdot\ \cdots\ \cdot a\cdot\ \cdots\ \cdot b\cdot\ \cdots\ \cdot(p-1)\),所以 \(ab\mid (p-1)!\);
当 \(a=b\) 时,\((p-1)!=1\cdot2\cdot\ \cdots\ \cdot a\cdot\ \cdots\ \cdot 2b\cdot\ \cdots\ \cdot(p-1)\).
综上,此时 \(p\mid(p-1)!\)。所以必要性成立;
再证充分性,即 \(p\) 是一个质数 \(\Rightarrow(p-1)!\equiv-1\pmod p\):
显然 \(p=2,3\) 时,命题成立;
对于任意质数 \(p\ge 5\),令 \(A=\{2,3,\cdots,p-2\}\),对于任意 \(a\in A\),令 \(B=\{a,2a,\cdots,(p-1)a\}\)。
任取 \(1\le x<y\le p-1\),那么 \(xa\neq ya\),且 \(xa,ya\in B\),由于 \((y-x)a\in B\),所以 \(p\nmid(ya-xa)\),所以对于任意 \(xa,ya\in B\),\(xa\not\equiv ya\pmod p\)。
所以 \(B\) 中任意两个元素模 \(p\) 不同余。
设 \(C=\{b|b=x\bmod p,x\in B\}\),则 \(C=\{1,2,3,\cdots,p-1\}\)。设 \(ax\equiv1\pmod{p}\),则:
\(x\neq1\),假设 \(x=1\),则 \(ax\equiv a\equiv1\pmod{p}\),即 \(a=1\notin A\),与 \(a\in A\) 矛盾;
同理,\(x\neq p-1\);
\(x\neq a\),假设 \(x=a\),则 \(a^2\equiv1\pmod{p}\),可知 \((a-1)(a+1)\equiv0\pmod{p}\),解得 \(a=1\) 或 \(a=p-1\),即 \(a\notin A\),舍去。
所以 \(a\in A\) 时,存在唯一的 \(x\in A\),使得 \(ax\equiv1\pmod p\),且任意两个 \(a,x\) 相互对应。
因此充分性成立。\(\Box\)
接下来,在了解了这 \(3\) 条性质之后,我们就要想想乘法逆元的求法了。
乘法逆元的求法
说了这么多,我们现在已经知道了模数,那么我们应该怎么求一个数 \(a\) 的逆元呢?
当然可以暴力解同余方程 \(ax\equiv1\pmod p\),时间复杂度为 \(\mathcal{O}(p)\),超时了别赖我 QwQ。
我们能不能用一种更快的算法来求逆元呢?当然可以,有下面的这 \(3\) 种求法供你选择:
扩展 Euclid 算法
我们考虑 \((2.3)\) 的不定方程,其中 \(x\) 是 \(a\) 的逆元。
一说到不定方程,我们马上就应该想到:用扩欧啊!
于是,这段代码就此产生了:
//exgcd 求逆元
int inv(int a, int p, int & x, int & k) {
if(p == 0) {
x = 1;
k = 0;
}
else {
inv(p, a % p, k, x);
k -= a / p * x;
}
return (x % p + p) % p; //注意求出的逆元可能是负数,我们要将其变为正的
}
它的时间复杂度为 \(\mathcal{O}(\log n)\)。
Fermat 小定理
Fermat 小定理是一个关于同余的问题,它的表述如下:
若 \(p\) 是质数且 \(a\perp p\),则 \(a^{p-1}\equiv 1\pmod p\)。
下面给出证明(数学证明警告!):
我们考虑一系列数 \(1,2,\cdots,p-1\),由于 \(p\) 是质数,所以它们均与 \(p\) 互质。
假如 \(a\perp p\),我们不妨设 \(a,2a,3a,\cdots,(p-1)a\),可以证明它们模 \(p\) 两两不同余(证明方法可以参照上面 Wilson 定理的证明),所以它们对 \(p\) 取模后,调整顺序,依旧为 \(1,2,\cdots,p-1\)。
故 \(a\cdot 2a\cdot 3a\cdot\ \cdots\ \cdot(p-1)a\equiv 1\cdot2\cdot3\cdot\ \cdots\ \cdot(p-1)\pmod p\)。
故 \(a^{p-1}\cdot(p-1)!\equiv(p-1)!\pmod p\),两边同时除以 \((p-1)!\),得 \(a^{p-1}\equiv 1\pmod p\)。\(\Box\)
当然,不看证明也是可以的。如果是要求逆元的话,我们只需要将这个定理小小地变形,则有 \(a\cdot a^{p-2}\equiv 1\pmod p\)。于是有 \(a^{-1}\equiv a^{p-2}\pmod p\),我们可以通过快速幂来求出 \(a^{p-2}\) 对 \(p\) 取模的结果了,时间复杂度依旧为 \(\Theta(\log n)\)。
线性求逆元
\(\mathcal{O}(\log n)\) 的算法似乎非常高效了,但是还不够高效。回到题目引入中的问题,如果 \(m\le 10^7\) 的话,就意味着我们需要至少 \(m\) 次计算阶乘中每一个数的逆元,每次都是 \(\mathcal{O}(\log m)\),总复杂度为 \(\mathcal{O}(m\log m)\),在 \(m\le 10^7\) 的时候可能会被卡掉。
我们依旧需要尝试减少重复计算同一个逆元的次数,将其时间复杂度变为 \(\mathcal{O}(1)\)。如下:
有一个很显然的结论:
因为商乘除数加余数等于被除数,所以有
代入 \((3.1)\) 式,移项,得:
两边同乘 \((p \bmod x)^{-1}\),得:
根据乘法逆元的定义,我们有
由 \((3.5)\) 式可知,如果我们已经求出了 \(1\) 到 \(p\bmod x\) 的逆元,那么我们就可以通过 \(\mathcal{O}(1)\) 递推转移过来 \(x\) 的逆元,这个过程中,求出 \(1\sim n\) 的逆元的时间复杂度是线性的 \(\Theta(n)\),而非 \(\mathcal{O}(n\log n)\),这样,就可以通过 \(n\le 10^7\) 大数据了。
代码如下:
int inv[p];
inv[1] = 1; //初始化 1 的逆元为 1
for(int i = 2; i <= p; ++i) {
inv[i] = (long long)(p - p / i) * (p % i) % p; //转移逆元
}
当然,虽然第三种算法的效率更高,但是它不大能用来求单个数的逆元,而且还浪费了 \(\mathcal{O}(n)\) 的辅助数组的空间复杂度。所以,选择哪种算法,要看具体题目情景里面是如何要求的。
有理数取模
那么,有了乘法逆元之后,我们就可以将取模的运算从整数推广到有理数。
假如一个有理数 \(q=\dfrac{a}{b}\),我们要求 \(q\bmod p\) 的值,其中 \(p\perp b\)。根据 \((1.5)\) 式,我们不难得出 \(q\equiv ab^{-1}\pmod p\)。
也就是说,我们可以将取模运算推广到有理数,这样,就可以将其用于求概率或者数学期望时候的取模了。
例题
本题目列表会持续更新。
- 洛谷 P3811 【模板】乘法逆元
- 洛谷 P5431 【模板】乘法逆元 2
- 洛谷 P1082 [NOIP2012 提高组] 同余方程
- 洛谷 P2613 【模板】有理数取余
- 洛谷 P4071 [SDOI2016] 排列计数

浙公网安备 33010602011771号