拓展欧几里得学习小记

前言

今天的比赛第一题就是解线性同余方程,大概思路是有了,就是在求非质数模的时候卡住了。这时我才开始后悔之前没有好好学学拓展 gcd ,然后弱弱地打了个欧拉函数求逆元,结果还WA掉了QAQ。比赛完后赶紧恶补了一下。

算法功能

拓展欧几里得算法( Extended Euclidean Algorithm )是基于欧几里得而来解一类特殊的线性丢番图方程( Diophantine equation )的算法。

Ax+By=gcd(A,B)

运用这个丢番图方程能有效解决许多数论问题。

算法解析

预备知识

欧几里得算法( gcd ),基本的解方程步骤。

算法步骤

和普通的欧几里得算法一样,拓展欧几里得算法先通过辗转相除法求得 gcd(A,B)
考虑在递归回退过程中,我们已经知道了 bx+(a mod b)y=gcd(A,B) 我们通过下列变形来得到方程 ax+by=gcd(A,B) 的解:

gcd(A,B)=b×x+(a mod b)×y=b×x+(aab×b)×y=a×y+b×(xab×y)

由此可得方程 ax+by=gcd(A,B) 的解为
x=y,y=xaby

如普通欧几里得算法,当 b=0 时, a=gcd(A,B) ,故这时返回方程解 x=1,y=0 即可(显然当 x,y 如刚才所述时, ax+by=gcd(A,B) )。然后像上述方法层层处理。
时间复杂度与普通欧几里得算法一样 O(logn2)
详细可见代码实现。

代码实现

void extended_gcd(int &a,int &b)
{
    if (!b)
    {
        gcd=a;
        a=1;
        b=0;
        return;
    }
    int a2=b,b2=a%b;
    extended_gcd(a2,b2);
    b=a2-(a/b)*b2;
    a=b2;
}

算法用途

求解模意义下乘法逆元

显然,求 a 关于 p 的乘法逆元,即解 ax1(mod p)(gcd(a,p)=1) 可以通过解方程 ax+py=1 来完成。因为方程可以变形为

ax+pyax+pyaxax=11(mod p)1py(mod p)1(mod p)

然后 x 其实就是 a 的逆元。
这种求逆元算法比费马小定理求逆元运用范围更广,因为 p 不一定是质数,只用与 a 互质。比欧拉定理求逆元更加高效。

解不定方程

证明:对于不定方程 ax+by=c ,可以证明方程有整数解当且仅当 gcd(a,b)|c

由裴蜀定理,方程 ax+by=gcd(a,b) 一定存在整数解。
由于 gcd(a,b)|a,gcd(a,b)|b ,故 gcd(a,b)|(ax+by)
如果方程有实数解(在实数范围内成立),那么用 c 替换 ax+by ,得到 gcd(a,b)|c
证毕。

求其中一组解

前提条件:该不定方程存在整数解
我们先求 ax+by=gcd(a,b)
d=cgcd(a,b) ,那么 x=dx,y=dy 一定是该不定方程的一组整数解。

你可能感兴趣的:(数论,OI,线性同余方程,拓展欧几里得)