关于exgcd

关于exgcd

对于二元一次不定方程\(ax+by=c\)

首先由裴蜀定理得,\(ax+by=gcd(a,b),\;gcd(a,b)\mid c\)

\[ax+by=gcd(a,b)\\ \]

\[ bx+(a\%b)y=gcd(b,a\%b) \\ \]

\[\because gcd(a,b)=gcd(b,a\%b) \\ \]

\[\therefore ax+by=bx+(a-\lfloor\frac{a}{b} \rfloor b)y \\ \]

\[\therefore ax+by=ay+(x-\lfloor\frac{a}{b} \rfloor y)b \]

void exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1;y=0;
        return;
    }
    exgcd(b,a%b);
    int tmp=x;
    x=y;
    y=tmp-a/b*y;
}

对于方程\(ax+by=gcd(a,b)\)两边同时乘以\(\frac{c}{gcd(a,b)}\),得到一组特解\(x_0 ,\; y_0\)

\[x_0=\frac{cx}{gcd(a,b)} \]

\[y_0=\frac{cy}{gcd(a,b)} \]

考虑推通解:

\[ax_0+by_0=c \]

\[a(x_0+kb)+b(y_0-ka)=c \]

\(d_x\) 为满足要求的 \(kb\) 的最小整数,\(d_y\) 为满足要求的 \(ka\) 的最小整数,因为 \(ka,kb\) 都是整数,当\(k=\frac{1}{gcd(a,b)}\)

\[d_x=\frac {b}{gcd(a,b)} \]

\[d_y=\frac {a}{gcd(a,b)} \]

方程通解可以表示为:

\[x=x_0+kd_x \]

\[y=y_0-kd_y \]

\(x>0\)\(k>\frac{-x_0}{d_x}\)

\(y>0\)\(k>\frac{y_0}{d_y}\)

\(x,y\)同时取到正整数,当且仅当

\[\lceil\frac{-x_0+1}{d_x}\rceil\leq \lfloor\frac{y_0-1}{d_y} \rfloor \]

\(x\)取得最小值时,\(y\)取得最大值

void work(){
    int a=read(),b=read(),c=read();
    int x=0,y=0;
    int g=exgcd(a,b,x,y);
    if(c%g!=0){//根据裴蜀定理,g不整除必无解
        printf("-1\n");
        return;
    }
    x=x*c/g;y=y*c/g;//求出特解
    int kx=b/g;
    int ky=a/g;
    int l=ceil(1.0*(-x+1)/kx);
    int r=floor(1.0*(y-1)/ky);
    if(l<=r){//两个都是正整数
        int num=r-l+1;//解的个数
        //当x取最小时,y对应取最大
        int minx=x+l*kx,maxy=y-l*ky;
        //当y取最小时,x对应取最大
        int miny=y-r*ky,maxx=x+r*kx;
        //printf("%lld %lld %lld\n",x,r,kx);
        printf("%lld %lld %lld %lld %lld\n",num,minx,miny,maxx,maxy);
    }
    else{
        int minx=x+l*kx;
        int miny=y-r*ky;
        printf("%lld %lld\n",minx,miny);
    }
}

posted @ 2022-10-26 15:35  blue_tsg  阅读(34)  评论(0编辑  收藏  举报