专栏文章
乘法逆元
算法·理论参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miqf0kwn
- 此快照首次捕获于
- 2025/12/04 03:43 3 个月前
- 此快照最后确认于
- 2025/12/04 03:43 3 个月前
乘法逆元的定义
乘法逆元是一个数 ,对于一个整数 ,满足以下公式:
即 和 的乘积对 取余后等于 。只有当 和 互质(),乘法逆元才存在。
费马小定理
适用条件:模数 必须是素数,且 和 互质。
公式推导
费马小定理告诉我们,如果 是素数且 和 互质,则:
将两边同时除以 ,得到:
因此,乘法逆元 可以用以下公式计算:
例子:求 3 在模 7 下的逆元
模数 ,且 是质数,使用公式 :
直接计算 ;
逐步计算 :
在模 下的逆元是 。
扩展欧几里得
适用条件:只要 和 互质即可,无需 是素数。
基本原理
扩展欧几里得算法不仅能求最大公约数,还能找到整数 和 使得:
当 时,方程变为:
将方程两边对 取模,那么 对 取模即 ,得到:
这表明 就是 的乘法逆元。
步骤
1. 普通欧几里得算法:求最大公约数(GCD)
我们先通过普通的欧几里得算法(辗转相除法)求出两个数的最大公约数。假设我们有两个整数 和 ,我们通过以下递归步骤来计算它们的 GCD:
- 最终直到某一余数为零为止,最后一个非零余数就是 。
2.反向推导:扩展过程
在计算 的过程中,我们逐步记录每一次除法的余数和商。然后通过反向推导的方式,得到整数 和 ,使得:
在 的情况下, 就是 对模 的乘法逆元。
例子:求 在模 下的逆元
-
用普通欧几里得算法(辗转相处法)求 :· ()· ()· ()最后 ,表示 和 互质,所以乘法逆元存在。
-
反向推导(扩展欧几里得算法):
从第二步()反向推导,计算 和 。
从第二步 得到:
然后,将第一步中的 带入上式:
因此得到:
,。表示 的乘法逆元是 。
乘法逆元的作用
这里列举两个常用的作用。
求解模线性同余方程
乘法逆元可以用来求解模线性同余方程:
当 和 互质时,方程有唯一解,解法是通过计算 在模 下的逆元
示例:
求解:
- 先求 在 下的逆元,
- 解方程:。
计算分数的模运算
在整数模运算中,分数无法直接处理。例如,计算 时,可以通过乘法逆元将其转化为:
就是 在模 下的逆元。
代码
费马小定理 + 快速幂
CPPint 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);}
扩展欧几里得
CPPint 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;
}
线性求 逆元
CPPvoid init(int m)
{
inv[1] = 1;
for(int i = 2; i <= m; ++i) inv[i] = (mod - mod / i) * inv[mod % i] % mod;
}
线性求 逆元(妙招)
CPPvoid 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;
}
线性求 逆元
CPPvoid 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;
}
总结
-
费马小定理:适合模数 是素数时使用,直接计算 。
-
扩展欧几里得算法:通用方法,无论模数是否是素数,只要 和 互质,都可以用。
-
OI Wiki: https://oi-wiki.org/math/number-theory/inverse/
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...