欧几里得:

int gcd(int a, int b)
{
    return !b ? a : gcd(b, a%b);
}
int lcm(int a, int b)//最小公倍数
{
    return a / gcd(a, b) * b;//先除后乘避免溢出
}

扩展欧几里得:

存在整数对(x,y)使得ax+by=gcd(a,b)
推导过程:
用递归求解扩展欧几里得,设已经求出了下一层递归的解,即:ax1+by1=gcd(a,b)的解(x1,y1)
又a%b=a−(a/b)∗b
将(x1,y1)代入到bx1+(a%b)y1=gcd(a,b)中,得
bx1+(a−(a/b)∗b)∗y1=gcd(a,b) => ay1+b(x1−(a/b)∗y1)=gcd(a,b)
当b=0时,显然有a∗1+b∗0=gcd(a,b)
写成代码,模板如下

int extgcd(int a, int b, int &x, int &y)
{
    int d = a;
    if(b != 0)
    {
        d = extgcd(b, a%b, y, x);
        y -= (a / b) * x;
    }
    else x = 1, y = 0;
    return d;
}

求解不定方程:

若c%gcd(a,b)=0,则存在整数对(x,y),使得a∗x+b∗y=c
通过上面的方法可得到一组特解(x0,y0)使得a∗x+b∗y=gcd(a,b),那么如何在无穷多个解中求出x,y最小正整数解。

证明:

首先 a∗x0+a∗k∗b/gcd(a,b)+b∗y0−a∗k∗b/gcd(a,b)=gcd(a,b)
即 a∗(x0+k∗b/gcd(a,b))+b∗(y0−k∗a/gcd(a,b))=gcd(a,b)
通解为x=x0+k∗b/gcd(a,b),y=y0−k∗a/gcd(a,b),其中k=...−2,−1,0,1,2...
在所有解中最小的正整数为(x0+b/gcd(a,b)),
所以对于方程a∗x+b∗y=c,最小正整数解(以x为例)为(x0∗c/gcd(a,b)+b/gcd(a,b))
注意:若b为负数,需将b转换为正数。

int cal(int a, int b, int c)
{
    int x, y;
    int gcd = extgcd(a, b, x, y);
    if(c % gcd != 0) return -1;
    x *= c/gcd;
    b /= gcd;
    if(b < 0) b = -b;
    int ans = x % b;
    if(ans <= 0) ans += b;
    return ans;
}

同余方程:

根据上面的内容,我们可以得到:

a∗x≡b(mod n),转化为a∗x+n∗y=b,当b时,方程有 gcd(a,n) 个解。
a∗x≡1(mod n),如果gcd(a,n)=1,则方程有唯一解。

解线性方程ax+by=c

bool cal(int a, int b, int c)
{
    int x0, y0;
    int d = extgcd(a, b, x0, y0);
    if(c % d) return false;
    int x = x0*c/d, y = y0*c/d;
    kx = b/d, ky = -a/d;
    return true; // 解集为:(x+kx*t, y+ky*t),t为整数
}