定义
若
a∗x≡1(modp),(a,p)=1
则称x为a的乘法逆元(mod p)。
//其中(a, b) 表示a和b的最大公约数。
有解条件
正如上面所言,当且仅当a和p互素时,a才有关于p的乘法逆元x。
求解方法
先总结一些这里要讲的四种情况
1. 拓展欧几里德求逆元
2. 费马小定理求逆元
3. 递推求[1, .., n]逆元
4. 不求逆元也可以解带除法的同余式
- 拓展欧几里德求逆元
欧几里德可以求ax + by = (a, b)中的x和y, 所以这里只要求出 ax + py = 1中的x即可, 这也是为什么(a, b)要等于1的原因。
LL Inv(LL a, LL p) {
LL x, y, d;
d = extgcd(a, p, x, y)
if(d == 1) return (x%p+p)%p;
return -1;
}
- 费马小定理求逆元
//费马小定理 a^(p-1) === 1(mod p)
//inv(a) === a^(p-2) (mod p);
LL pow_mod(LL a, LL b, LL mod) {
LL r = 1; a %= mod;
while(b) {
if(b&1) r = (r*a) % mod;
a = (a*a) % mod;
b >>= 1;
}
return r;
}
LL Inv(LL a, LL p) { //前提是a,p互素且p为素
return pow_mod(a, p-2, p);
}
费马小定理的定义如下:
ap−1≡1(modp),(a,p)=1
当且仅当a与p互素时成立, 故上式可以变形为
a∗ap−2≡1(modp)
那么a的逆元就是 ap−2 了。
这里使用快速幂加速计算。
- 递推求[1, .., n]逆元
//O(n)时间求[1,,n]内所有数的逆元(n < p 且 p 为素)
int inv[maxn];
void invTable(int n, int p, int inv[]) {
inv[1] = 1;
for(int i = 2; i <= n; ++i)
inv[i] = (p-p/i) * inv[p%i] % p;
}
递推式的证明如下
设如下变量:
inv[i]: i 的逆元(mod p), 其中i < p, inv[i] < p。
k : p / i
b : p % i //即 p = k * i + b, 显然b < i。则要证 inv[i]=(p−pi)∗inv[p(modi)](modp)
即证 inv[i]=(p−k)∗inv[b](modp)
下证:
易知
k∗i+b≡0(modp)
两边除以i得k+bi≡0(modp)
即(保证同余式两边皆为最小剩余)b∗inv[i]≡−k(modp)≡p−k(modp)
两边除以b得inv[i]≡p−kb(modp)
即inv[i]≡(p−k)∗inv[b](modp)
得证。
另外补充一点也许很重要的知识:[1,,p-1]的逆元(mod p)对应[1,,p-1]的每一个数,即它们都是p的最小剩余系(除去0外)。
关于这一点的证明, 显然逆元也都是最小剩余,所以只要使用反证法证得任意两个数的逆元不相等即可。
- 不求逆元也可以解带除法的同余式(x为最小剩余即 x < p)
x≡ab(modp)
等价于
x=a(mod(b∗p))b
此式的证明如下
由
x≡ab(modp)
得ab=k∗p+x
其中k为任意整数, x < p, 移项得
a=k∗p∗b+x∗b
将此转为同余式得x∗b≡a(modp∗b)
将b除过去得x=a(mod(p∗b))b
得证
注意模数(b*p)可能会很大,取模之后不一定是int型(可用快速乘取模解决)。
应用
主要用于求带除法的同余式。