乘法逆元
wu_zi_jin0917 · · 个人记录
乘法逆元
定义
对于线性同余方程
逆元的一个最重要的用处是用于处理模意义下的除法,它有性质如下:
由于模意义下混合运算中的除法无法直接取模,逆元成为了处理该类除法的重要工具
扩展欧几里得算法求逆元
前置知识:扩展欧几里得算法
我们知道(不知道的点上面的链接),扩展欧几里得算法可以用于求解形如
由逆元的定义可知,我们可以通过扩展欧几里得算法迅速求出单个乘法逆元
代码如下:
int ex_gcd(int a, int b, int& x, int& y)
{
if (b == 0)
{
x = 1;
y = 0;
return a;
}
int d = ex_gcd(b, a % b, x, y);
int temp = x;
x = y;
y = temp - a / b * y;
return d;
}
bool liEu(int a, int b, int c, int& x, int& y)//求解线性同余方程
{
int d = ex_gcd(a, b, x, y);
if (c % d != 0) return 0;
int k = c / d;
x *= k;
y *= k;
return 1;
}
费马小定理求逆元
费马小定理: 对于素数
证明有些复杂,这里只放链接
知道了费马小定理的内容,我们可以完成如下推导:
对于素数b,因为
所以
所以
因此,我们可以使用快速模幂在
代码如下:
int qpow(long long a, int b) {
int ans = 1;
a = (a % p + p) % p;
for (; b; b >>= 1) {
if (b & 1) ans = (a * ans) % p;
a = (a * a) % p;
}
return ans;
}
线性处理逆元
我们发现,如果每次都仅仅求单个逆元,多次查询的时间太慢了。我们是否有办法,在
首先,
考虑如何由一个已知逆元推出
两边同乘
移项得:
由
因为
所以可以得到如下递推式
代码实现如下:
inv[1] = 1;
for (int i = 2; i <= n; ++i)
inv[i] = (long long)(p - p / i) * inv[p % i] % p;//这里是负数取模
于是,我们在线性时间复杂度内,递推出了1~n的逆元