定义
若在mod p意义下,对于一个整数a,有ax≡1 (mod p),那么这个整数x即为a的乘法逆元,同时a也为x的乘法逆元。
求解方法
- 费马小定理
当a,p互质并且p为质数时,满足ap-1≡1(mod p)
证明:
因为
ax≡1(mod p)
ap-1≡1(mod p)
根据同余的性质,所以
ax≡ap-1(mod p)
x≡ap-2(mod p)
即,a对p的乘法逆元为ap-2
证毕
所以,只用打一个快速幂就可以啦:-D
但要注意的是此方法限制了p只能为质数
- 解不定方程
首先先说线性同余方程
给定整数a,b,p,求解一个整数x满足ax≡b (mod p),或者给出无解。
因为未知数指数为1,所以称为线性同余方程
ax≡b (mod p)等价于ax-b是p的倍数
设y为倍数,那么ax-b=py,移项得:ax-py=b
又因为y可以为负数,所以改写为ax+py=b
求解x,我们只用解不定方程即可
此方程当且仅当gcd(a,p)整除b的时候有整数解
具体地讲,求a对p的逆元x,因为x满足ax≡1 (mod p)
把它化成不定方程的形式为ax+py=1
当且仅当gcd(a,p)=1的时候有整数解
所以此时不必保证p一定为质数,只用保证a,p互质即可
可以利用扩展欧几里得算法求解x
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int a,b,p; 5 void exgcd(int a,int b,int &x,int &y){//扩欧 6 if(b==0){ 7 x=1; 8 y=0; 9 }else{ 10 exgcd(b,a%b,x,y); 11 int t=x; 12 x=y; 13 y=t-a/b*y; 14 } 15 } 16 int gcd(int a,int b){ 17 return b==0?a:gcd(b,a%b); 18 } 19 int main(){ 20 cin>>a>>b>>p; 21 int x,y; 22 exgcd(a,p,x,y); 23 if(b%gcd(a,p)==0){ 24 cout<<(x%p+p)%p<<endl; 25 }else{ 26 cout<<"no solution"; 27 } 28 return 0; 29 }
- 线性递推
现欲求a对p的逆元x(x=a-1)
设p=ak+r(1<r<i<p) k就是p/a的商(可以表示为⌊p/a⌋) r是余数
将这个式子转化为同余式就变成了ak+r≡0 (mod p)
同时乘a-1r-1得,r-1k+a-1≡0 (mod p)(a-1后文用x代替)
再根据同余的同加性得,x≡-r-1k (mod p)
所以 x≡-⌊p/a⌋(p%a)-1 (mod p)
再进一步即可化为 x=(p-⌊p/a⌋)(p%a)-1 (mod p)
于是,我们就可以愉快的用递归的方法求解a的逆元啦
大家可能已经体会到了,这种方法在求一串连续的数的逆元时会比前面的方法快很多
下面就举个栗子:[模板]乘法逆元
此题就是求1~n中所有数的逆元 直接用线性递推的方法就好
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int n,p; 5 const int maxn=3e6+5; 6 ll inv[maxn]; 7 int main(){ 8 scanf("%d%d",&n,&p); 9 inv[1]=1; 10 printf("1 "); 11 for(int i=2;i<=n;i++){ 12 inv[i]=(ll)(p-p/i)*inv[p%i]%p; 13 printf("%d ",inv[i]); 14 } 15 return 0; 16 }
【模板】乘法逆【模板】乘
_____________ヾ(❀^ω^)ノ゙___✿✿✿________‧★,:*:‧( ̄▽ ̄)/‧:*°★*___________