![782512fb8af2030e00b3aa9fc63eea89.png](https://i-blog.csdnimg.cn/blog_migrate/7cd6e0e4688dd95f7d288d8bcba7bf1a.jpeg)
https://zhuanlan.zhihu.com/p/105467597在数论中,如果
逆元有什么用呢?我们常常遇到一些题目要求结果对一个大质数
![a7aa930fd756cb726e4536d71ac13c8b.png](https://i-blog.csdnimg.cn/blog_migrate/f4ddf09616b699c146e3b25b384efb5e.jpeg)
但遇到除法时,就麻烦了:
![ad5626b6898418c37dcac0f092815b4f.png](https://i-blog.csdnimg.cn/blog_migrate/3d1040d46732cf5479924a800e146350.jpeg)
为了解决模意义下的除法问题,我们引入了逆元。
实际上在模
![89134ebf56aa0b5d3b003c45082734c5.png](https://i-blog.csdnimg.cn/blog_migrate/aa7facb79e4ab87c6e455987c5aeae95.jpeg)
这里介绍三种计算逆元的方法:拓展欧几里得,费马小定理,线性递推。
拓展欧几里得
这种方法上一节已经介绍了,那道“同余方程”其实就是在求逆元。实际上,这就是最常用的求逆元的方法。代码如下:
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;
}
ll inv(ll a, ll p)
{
ll x, y;
if (exgcd(a, p, x, y) != 1) // 无解的情形
return -1;
return (x % p + p) % p;
}
费马小定理
费马小定理是数论里的重要定理,叙述如下:
若是质数,且
,则有
![]()
从逆元的定义推导,可得
于是对
inline ll qpow(ll a, ll n, ll p)// 快速幂
{
ll ans = 1;
while (n)
{
if (n & 1)
ans = ans % p * a % p;
a = a % p * a % p;
n >>= 1;
}
return ans;
}
inline ll inv(ll a, ll p)
{
return qpow(a, p - 2, p);
}
线性递推
以上两种方法都是常用的求逆元方法,但是,洛谷上的这道毒瘤模板题,必须要用特殊的方法:
(洛谷P3811 【模板】乘法逆元)
题目背景
这是一道模板题 题目描述
给定求
中所有整数在模
输入格式意义下的乘法逆元。
一行两个正整数输出格式。
输出行,第
行表示
在模
下的乘法逆元。
因为这道题要求一系列的乘法逆元,而且数据范围是
设
在模
移项整理得
则
即
其实和拓展欧几里得还是有不少相似之处的。我们可以用记忆化搜索的方法,减少多次查询的时间复杂度(空间换时间)。(递推亦可,其实就这题而言递推更好)
// 多次对不同的p使用需要清空Inv数组
ll Inv[MAXN] = {0, 1};
inline ll mod(ll a, ll p)
{
return (a % p + p) % p;
}
ll inv(ll a, ll p)
{
if (Inv[a])
return Inv[a];
Inv[a] = mod(-p / a * inv(p % a, p), p);
return Inv[a];
}
https://zhuanlan.zhihu.com/p/105467597zhuanlan.zhihu.com