乘法逆元、更相减损术与辗转相除法、欧几里得算法和拓展欧几里得算法

乘法逆元与其计算基础

本文描述 乘法逆元、更相减损术、辗转相除法和拓展欧几里得算法。由于这几项内容是相互关联,可以层次深化的,因此此处放在一起描述。各章节之间存在递进关系,请看官留心逻辑关联。

更相减损术与辗转相除法

两个算法多用于计算最大公约数,经由拓展方式处理可以用于计算乘法逆元。以下为算法描述:

更相减损术

记数字 A=8,数字 B=4,计算二者的最大公约数。

更相减损术的核心思想是 两个数既然有最大公约数(gcd),那么二者必然均由 最大公约数的数倍表示,即 A = k 1 × g c d A = k_1\times gcd A=k1×gcd B = k 2 × g c d B = k_2 \times gcd B=k2×gcd。因此,二者只要反复互减,最终将化简至一个 不可分元,即最大公约数。

辗转相除法

辗转相除法基于 更相减损术 的逻辑进行描述,依然是两个数字均为最大公约数的 数倍。两个数除了是最大公约数的倍数之外,互相之间也可能呈现一定的倍数关系。若有 A = k ′ × B + g c d A = k^{'} \times B + gcd A=k×B+gcd,此时,二者计算 A % B = g c d A\%B = gcd A%B=gcd即可得到结论。主要依据的规则为:

  • g c d ( A , B ) = g c d ( B , A % B ) gcd(A, B) = gcd(B, A\%B) gcd(A,B)=gcd(B,A%B)
    其中,不妨设A>B;

较之于更相减损术每次从两个数中减去数倍的 gcd,辗转相除法每次删掉数倍的 k × g c d k \times gcd k×gcd,因此收敛速度快一些。

乘法逆元

以上两种算法用于描述最大公约数。因为两个数都是由最大公约数的数倍构成,显然有:
∃ k 1 , k 2 ∈ Z k 1 × A + k 2 × B = g c d \exist k_1,k_2\in Z\\ k_1\times A + k_2\times B = gcd k1,k2Zk1×A+k2×B=gcd

乘法逆元是对于式子 k 1 × A + k 2 × B = g c d k_1\times A + k_2\times B = gcd k1×A+k2×B=gcd一种特殊情况的描述,即 A − 1 × A + k 2 × B = 1 ( m o d    B ) A^{-1}\times A + k_2\times B = 1 (mod\ \ B) A1×A+k2×B=1(mod  B),则 A , A − 1 A, A^{-1} A,A1互为乘法逆元。定义描述为:

若在mod p意义下,对于一个整数a,有a*b≡1(mod p),那么这个整数b即为a的 乘法逆元,同时a也为b的乘法逆元。一个数有逆元的充分必要条件是gcd(a,p)=1,此时a才有对p的乘法逆元。

摘自:https://www.cnblogs.com/-citywall123/p/10673212.html

**提出乘法逆元的主要目的是用于描述特定的余数值。**假设我们知道:

  1. A % d = c A \% d = c A%d=c,其中 c , d c,d c,d已知。
  2. 而且 g c d ( B , d ) = 1 gcd(B, d) = 1 gcd(B,d)=1 ,即存在 B 的乘法逆元,使得 B − 1 B % d = 1 B^{-1}B\%d = 1 B1B%d=1
  3. 那么对式子放缩可以得到 c × B − 1 B % d = c c\times B^{-1}B\%d = c c×B1B%d=c;
  4. 由此可得 A = c ⋅ B − 1 B + k d A = c\cdot B^{-1}B + kd A=cB1B+kd,实现了将A表示为B的函数;

因此,当题目中提供一些B的特殊性质的时候,就可以使用题目中提供的条件,利用变量B进行求解。
乘法逆元的计算方法目前常用有两种,一种是费马小定理(如下),一种是拓展欧几里得。

费马小定理认为,p为质数的时候(即特殊情况下),有 b p − 1 % p = 1 b^{p-1}\%p=1 bp1%p=1,显然,逆元为 b p − 2 b^{p-2} bp2

ll pow(ll a, ll n, ll p)    //快速幂 a^n % p
{
    ll ans = 1;
    while(n)
    {
        if(n & 1) ans = ans * a % p;
        a = a * a % p;
        n >>= 1;
    }
    return ans;
}

ll niyuan(ll a, ll p)   //费马小定理求逆元
{
    return pow(a, p - 2, p);
}

拓展欧几里得算法

欧几里得算法用于计算最大公约数,实际上就是辗转相除法。代码如下:

int getGCD(int a, int b){
    int gcd = 1;
    if (b == 0){
        gcd = a;
        return gcd;
    }
    // gcd(a, b) = gcd(b, a%b);
    gcd = getGCD(b, a%b);
    
    return gcd;
}

拓展欧几里得算法可以用于计算乘法逆元。主要使用欧几里得算法中的递推关系:

  1. g c d = k 1 ⋅ A + k 2 ⋅ B gcd = k_1 \cdot A+k_2\cdot B gcd=k1A+k2B;
  2. g c d = k 1 ⋅ B + k 2 ⋅ A % B = k 1 ⋅ B + k 2 ⋅ ( A − A B ) gcd = k_1\cdot B+k_2\cdot A\%B = k_1\cdot B + k_2\cdot (A - \frac{A}{B}) gcd=k1B+k2A%B=k1B+k2(ABA)
  3. 化简,提出公因式 k 1 , k 2 k_1, k_2 k1,k2,得到基于下层递归结果计算上层递归的递推算式: k 2 = k 1 k_2 = k_1 k2=k1 k 1 = k 2 × ( A − A B ) k_1=k_2\times(A-\frac{A}{B}) k1=k2×(ABA)
void exgcd(ll a, ll b, ll &x, ll &y)    //拓展欧几里得算法
{
    if(!b) 
        x = 1, y = 0;
    else
    {
        exgcd(b, a % b, y, x);
        y -= x * (a / b);
    }
}

ll niyuan(ll a, ll b)   //求a对b取模的逆元
{
    ll x, y;
    exgcd(a, b, x, y);
    return (x + b) % b;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值