模板 - 扩展欧几里得算法

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

inline int gcd(int a,int b){
    if(b==0)
        return a;
    else{
        while(int i=a%b){
            a=b;
            b=i;
        }
        return b;
    }
}

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

//解线性同余方程: ax+by=c
bool _LCE(int a, int b, int c, int &x, int &y) {
    //printf("%d*x + %d*y = %d\n",a,b,c);
    int x0,y0;
    int d=ex_gcd(a,b,x0,y0);
    if(c%d!=0){
        //无解
        return 0;
    }
    //ax0+by0=gcd(a,b)
    int k=c/d;
    x=x0*k;
    y=y0*k;
    //ax+by=c是一组解
    //x'=x+bt,y'=y+at,是方程的所有解,对所有整数t成立
    //printf("%d*%d + %d*%d = %d\n",a,x,b,y,c);
    return 1;
}

//解线性同余方程 ax = b mod n
//这个是和 ax + ny mod b等价,注意变量
int LCE(int a,int b,int n){
    //printf("%d*x = %d mod %d\n",a,b,n);
    int x0,y0;
    if(_LCE(a,n,b,x0,y0)){
        int t=n/gcd(a,n);
        //printf("gcd(%d,%d)=%d\n",a,n,gcd(a,n));
        //printf("x0=%d,t=%d\n",x0,t);
        //x=x0+k*(n/gcd(a,n)),对任意整数k都是解
        //最小非负整数解
        int x=(x0%t+t)%t;
        //printf("%d*%d = %d mod %d\n",a,x,b,n);
        return x;
    }
    else{
        //无解
        return -1;
    }
}

int main() {
#ifdef Yinku
    freopen("Yinku.in","r",stdin);
#endif // Yinku
    int a,b;
    while(~scanf("%d%d",&a,&b)) {
        printf("%d\n",LCE(a,1,b));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Yinku/p/10969922.html