浅析乘法逆元
1.模的运算律
先来一波模运算律表:
运算律 | 内容 |
---|---|
交换律 |
(a+b)%p=(b+a)%p
(a×b)%p=(b×a)%p |
结合律 |
((a+b)%p+c)%p=(a+(b+c)%p)%p
((a×b)%p×c)%p=(a×(b×c)%p)%p |
分配率 |
((a+b)%p×c)%p=((a×c)%p+(b×c)%p)%p
(a×b)%p=(a%p×b%p)%p (a+b)%p=(a%p+b%p)%p (a−b)%p=(a%p−b%p)%p |
2.定义
有的时候我们需要对一个数取模,这很简单。但是在取模的过程中出现了除数,那么取模就没这么简单了:
但万一是 7100002%4 计算机可无法先计算 7100002 再 (mod4) ,因为数字太大了。
这个时候我们就需要用到乘法逆元了,事实上: 7100002=(7∗3)10000 。我们运用模的运算律可以通过边乘边取模即可得到答案,其中3是7在 (mod4) 意义下的逆元。
关于逆元的严格定义如下:
若整数b,m互质,并且b∣a,则存在整数x,使得a/b≡a∗x(modm),则称x为b的模m乘法逆元,记为b−1(modm)
3.求解
3.1费马小定理1
因为
a/b≡a∗b−1≡a/b∗b∗b−1(modm)
,所以
b∗b−1≡1(modm)
2
如果m是质数(此时我们用符号
p
代替
到最后我们可以用快速幂来迅速求出
int ksm(int a,int b,int p) {
int ans=1;
for(; b; b>>=1,a=a*a%p)if(b&1)ans=ans*a%p;
return ans;
}
时间复杂度是 O(logn)
3.2扩展欧几里得算法
扩展欧几里得算法的具体内容参考我写的:浅析扩展欧几里得算法(exgcd)
根据逆元的定义我们要求的是
a∗x≡1(modm)
关于x的同余方程,其中x为a在
(modm)
意义下的逆元
事实上
变形①式得:
既然 a,b 都已知,就不难求出 x和y 了(但要注意 y 的系数
int exgcd(int a,int b,int &x,int &y) {
if(b) {
int c=exgcd(a,b,y,x);
y-=a/b*x;
return c;
} else {
x=1;
y=0;
return a;
}
}
时间复杂度是 O(lnn)
3.3线性求解
当我们需要求解大量的逆元的时候,前两种的方法时间复杂度都要乘以
n
,时间复杂度都不是很理想。所以我们就用
所以我们得到:
那么只要建一个数组inv,初始值inv[1]=1。所以代码如下:
for(int i=2; i<=n; i++)
inv[i]=-(p/i)*inv[p%i];