逆元 与 扩展欧几里得算法 (very important)
^ - ^ 点个赞再走吧~~
^ - ^ 点个赞再走吧~~
^ - ^ 点个赞再走吧~~
欧几里得定理 :给定任意 a , b ,一定存在x, y 使得 ax +by = gcd(a,b)
公式 : ax +by = gcd(a,b);
1) 利用欧几里得的过程
给定 n ,对正整数 ai , bi,对于每对数,求出一组 xi , yi,使其满足
ai * xi + bi * yi = gcd(ai,bi)
推导: ax + by = d =>
bx + ( a %b )y = d =>
bx + (a - a/b * b)y= d =>
b( x - a/b *y ) + ay == d == ax + by
得 x = y, y = y - a/b *x
核心代码:
int edgcd(int a,int b,int &x,int& y){
if(!b){
x=1,y=0;
return a;
}
int d = edgcd(b,a%b,x,y);
int yy =y;
y= x-a/b*y;
x = yy;
return d;
}
完整代码 :
#include<iostream>
#define int long long
using namespace std;
int edgcd(int a,int b,int &x,int& y){
if(!b){
x=1,y=0;
return a;
}
int d = edgcd(b,a%b,x,y);
int yy =y;
y= x-a/b*y;
x = yy;
return d;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--){
int a,b;
cin>>a>>b;
int x = 1,y= 2;
//为什么x和y不用赋初值。因为递归进入之后一定会递归到最低层,此时x=1,y=0
//然后在这个基础上,会回溯,所以无论x和y赋值什么,都会从1 0开始计算
edgcd(a,b,x,y);
cout<<x<<' '<<y<<endl;
}
return 0;
}
^ - ^ 点个赞再走吧~~
^ - ^ 点个赞再走吧~~
^ - ^ 点个赞再走吧~~
乘法逆元的定义
若整数 b,m 互质,并且对于任意的整数 a,如果满足 b|a 则存在一个整数 x,使得 a /b ≡ a * x ( mod m ) 则称 x 为 b的模 m 的 乘法逆元,记为 b^−1 ( mod m)
b 存在乘法逆元的充要条件是 b 与模数 m 互质。当模数 m 为质数时,b^(m−2) 即为 b 的乘法逆元。
2) 快速幂逆元 (important)
思路:当模m是质数时,x 的 逆元 就等于x的m-2次方 即x^-1 = x^(m-2)
思路:利用快速幂,快速求出x的m-2次方
核心代码:
while(b){
if(b&1)sum = sum*a%p;
b>>=1;
a = a*a%p;
}
完整代码:
#include<iostream>
#define int long long
using namespace std;
int a,b,p;
signed main(){
int t;
cin>>t;
while(t--){
cin>>a>>p;
int b = p-2;
int sum = 1;
while(b){
if(b&1)sum = sum*a%p;
b>>=1;
a = a*a%p;
}
if(a%p)cout<<sum<<endl;
else cout<<"impossible"<<endl;
}
return 0;
}
3) 欧几里得求线性同余方程
给定a,b m 满足 a * x ≡ b (mod m)
推导: ax %m = b%m =>
ax %m = ax%m , (b + my) %m = b%m =>
ax = b + my =>
ax - my = b =>
ax + my = b
所以这其实是在利用扩展欧几里得公式求 x, y
但是必须保证 (a,m)|b 也就是a和m的最大公约数能整除b
所以只需要求 ax + my = gcd( a , m ) = d
最后答案等于 x *b/d
核心代码 :
int edgcd(int a,int b,int &x,int& y){
if(!b){
x=1,y=0;
return a;
}
int d = edgcd(b,a%b,x,y);
int yy =y;
y= x-a/b*y;
x = yy;
return d;
}
int d = edgcd(a,m,x,y);;
if(b%d)cout<<"impossible"<<endl;
else cout<<x*(b/d)%m<<endl;
完整代码 :
#include<iostream>
#define int long long
using namespace std;
int edgcd(int a,int b,int &x,int& y){
if(!b){
x=1,y=0;
return a;
}
int d = edgcd(b,a%b,x,y);
int yy =y;
y= x-a/b*y;
x = yy;
return d;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
//转化为,ax+my = b
//只要 d能够整除b,也就是说b是d的倍数,那么就能用扩展欧几里得定理
//ax +my = (a,m) = d;
//最后输出x*(b/d);
while(t--){
int a,b,m;
cin>>a>>b>>m;
int x, y;
int d = edgcd(a,m,x,y);;
if(b%d)cout<<"impossible"<<endl;
else cout<<x*(b/d)%m<<endl;
}
return 0;
}
4) 扩展欧几里得求逆元
若是 b|a 且b与m互质 如果满足 a/b ≡ a*x (mod m)
则 称 x 是b模m的逆元
我们要求x
推导:
(a/b)%m = a*x%m
a/b = ax + my
ax +my = a/b
即 abx+ mby = a;
d = gcd( ab, mb);
所以b的逆元,就等于 x*( a / d )
通过欧几里得定理求出x
核心代码:
//edgcd 是扩展欧几里得函数。在上面已经出现过了
int d = edgcd(a*b,m*b,x,y);;
if(a%d)cout<<"impossible"<<endl;
else cout<<x*(a/d)%m<<endl;
5 求逆元总结
( 1 ) 当m是质数的时候,b的逆元就等于 b^(m-2),用快速幂来求解
( 2 ) 当m不确定的时候 用扩展欧几里得定理对
a/b ≡ a*x (mod m) 变形为 abx+ mby = a;
d = gcd( ab, mb);
答案就是 x*( a / d )