逆元和除法同余
逆元和除法同余
一、为什么需要逆元
在算法竞赛中,计算结果经常需要对一个大质数取模,比如 % 1000000007。
加、减、乘都可以直接对中间结果取模:
- 加法:
(a + b) % MOD - 减法:
(a - b + MOD) % MOD - 乘法:
(a * b) % MOD
但除法不行。
举个例子,计算 (10 / 5) % 3:
- 正确结果:
10 / 5 = 2,2 % 3 = 2 - 如果先取模再除:
10 % 3 = 1,5 % 3 = 2,1 / 2 = 0(整数除法),结果变成 0
结果对不上。原因是同余运算对除法不封闭。
那怎么办?这就需要乘法逆元。
二、逆元的定义
若整数 a 和 m 互质(gcd(a, m) = 1),且存在整数 x 使得:
a × x ≡ 1 (mod m)
则称 x 是 a 在模 m 意义下的乘法逆元,记作 a⁻¹。
通俗理解:逆元就是模意义下的倒数。
三、用逆元实现除法同余
如果你想计算 (a / b) % MOD,需要满足三个条件:
a / b必须能整除(每次除法都要保证绝对能整除)MOD必须是质数(比如1000000007,998244353)b和MOD互质(即gcd(b, MOD) = 1)
题目给定的数据一定会满足上面三点。满足后,有结论:
(a / b) % MOD = ((a % MOD) × (b 的逆元)) % MOD
也就是说:除法变成了乘以逆元。
而 b 的逆元怎么求?
b 的逆元 = b^(MOD-2) % MOD
这是基于费马小定理的结论,直接用快速幂计算即可。
四、模板代码
typedef long long ll;
const ll MOD = 1e9 + 7;
// 快速幂计算 (a^b) % MOD
ll qpow(ll a, ll b)
{
ll res = 1;
a %= MOD;
while (b > 0)
{
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
// 求 b 的逆元(要求 MOD 是质数,且 b 与 MOD 互质)
ll inv(ll b)
{
return qpow(b, MOD - 2);
}
// 计算 (a / b) % MOD
ll div_mod(ll a, ll b)
{
return (a % MOD) * inv(b) % MOD;
}
int main()
{
ll a = 10, b = 5;
cout << div_mod(a, b) << endl; // 输出 2
return 0;
}
五、逆元的线性递推
(1) 连续数字逆元的线性递推
在 % p 意义下,
1、2、3 . . . n,求每个数的逆元
用 inv[i],代表 i 的逆元 (直接记住,不要问为什么)
inv[1] = 1;
inv[i] = (int)(p - (long) inv[p % i] * (p / i) % p); // 从左往右线性递推
(2) 连续阶乘逆元的线性递推
在 % p 意义下,
1!、2!、3! . . . n!,求每个数的逆元,
用 inv[i],代表 i! 的逆元(比较简单,容易理解)
inv[i] 相当于 等价于1 / i !, 那么int[i - 1] 等价于 1 / (i - 1)!, 不就是inv[i] * (i) % MOD
做法:先求 n! 乘法同余的结果,假设为 a,然后求 a 的逆元,假设为 b
inv[n] = b;
inv[i] = ((long) (i + 1) * inv[i + 1]) % MOD; // 从右往左线性递推
*六、扩展:扩展欧几里得求逆元
当 MOD 不是质数时,用扩展欧几里得求逆元:
// 扩展欧几里得:求 ax + by = gcd(a, b) 的一组解
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if (b == 0)
{
x = 1; y = 0;
return a;
}
ll d = exgcd(b, a % b, y, x);
y -= (a / b) * x;
return d;
}
// 求 a 在模 m 意义下的逆元(要求 gcd(a, m) = 1)
ll inv_exgcd(ll a, ll m)
{
ll x, y;
ll d = exgcd(a, m, x, y);
if (d != 1) return -1; // 逆元不存在
return (x % m + m) % m;
}
七、总结
逆元就是模意义下的倒数。
计算
(a / b) % MOD:
- 先求
b^(MOD-2) % MOD(b 的逆元)- 再算
(a % MOD) * inv(b) % MOD
左神特别强调:这部分记住用法和模板即可,证明过程没有太多扩展性,当做原子技能使用。

浙公网安备 33010602011771号