逆元 与 扩展欧几里得(超级详细,c++)

逆元 与 扩展欧几里得算法 (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

原题链接:877. 扩展欧几里得算法 - AcWing题库

​ 核心代码:

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
#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)

原题链接:876. 快速幂求逆元 - AcWing题库

思路:利用快速幂,快速求出x的m-2次方

核心代码:

 while(b){
            if(b&1)sum = sum*a%p;
            b>>=1;
             a = a*a%p;
        }

完整代码:

#include
#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

原题链接:878. 线性同余方程 - AcWing题库

核心代码 :

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
#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 )

你可能感兴趣的:(Acm算法,c++,c++,开发语言,算法)