逆元相关知识
乘法逆元(mod 在C++里是%)
定义:
满足a*k≡1 (mod p)的k值就是a关于p的乘法逆元。
为什么要有乘法逆元呢?
当我们要求
a
b
%
p
\frac{a}{b}\%p
ba%p的值,且
a
a
a,
b
b
b都很大,无法直接求得
a
b
\frac{a}{b}
ba的值,必须在之前mod时(因为
a
b
%
p
\frac{a}{b}\%p
ba%p不等于
a
%
p
b
%
p
\frac{a\%p}{b\%p}
b%pa%p),我们就要用到乘法逆元。
我们可以通过求
b
b
b关于
p
p
p的乘法逆元
k
k
k,将
a
a
a乘上
k
k
k再模
p
p
p,即
a
∗
k
%
p
a*k\%p
a∗k%p。其结果与
a
b
%
p
\frac{a}{b}\%p
ba%p等价。
也就是
k
=
b
−
1
(
m
o
d
p
)
k=b^{-1} (mod p)
k=b−1(modp)
证:(其实很简单。。。)
- 根据bk≡1 (mod p)有bk=p*x+1。
- k=(p*x+1)/b。
- 把k代入(a*k)%p,得:
- (a*(p*x+1)/b)%p
- =((apx)/b+a/b)%p
- =[((apx)/b)%p +(a/b)]%p
- =[(p*(a*x)/b)%p +(a/b)]%p
- //p*[(a*x)/b]%p=0
- 所以原式等于:(a/b)%p
根据欧几里德算法
代码如下:
void Exgcd(int a,int b,int &x,int &y){if(!b) x=1,y=0;else Exgcd(b,a%b,y,x),y-=a/b*x;}
int main(){
cin>>a>>b>>p;//(a/b)%p
Exgcd(b,p,x,y);
int ni=(x+p)%p;//防止出现负数
printf("%d就是逆元\n",ni);
return 0;
}
费马小定理求逆元
a p − 1 = 1 ( m o d p ) a^{p-1}=1(mod p) ap−1=1(modp) ( p p p是素数)
那么 a / b a/b a/b关于 p p p的逆元就是 b p − 2 b^{p-2} bp−2(因为 b p − 2 = 1 b b^{p-2}=\frac{1}{b} bp−2=b1)
快速幂求一下就可以了,但是如果p不是素数,只能用exgcd求逆元(或没有逆元)。
线性求逆元
求i的逆元。
可得p%i+(p/i)*i=p
- 令a=p%i,b=p/i;
- a+b*i=p
- a+b*i≡0(mod p)
- b*i≡-a(mod p)
- i^-1=-b/a
所以i的逆元:-(p/i)*(p%i)^-1
这样就可以O(n)求出所有逆元了
代码如下:
(因为1^(-1)=1,所以初始化inv[1]=1)
for(inv[1]=1,i=2;i<=n;i++) inv[i]=(p-p/i)*inv[p%i]%p;
所以最后O(1)出答案。