扩展GCD学习笔记

原理

//一般gcd
ll gcd(ll a,ll b){
    return b==0?a:gcd(b,a%b);
}

当递归得到b=0时,得到gcd(a,b)=a,因此方程变为ax+0y=a,此时x=1,y=0是方程的一组特解

模板

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

例题

P5656 解二元一次不定方程

题意:

给定不定方程

ax+by=c

若该方程无整数解,输出 -1
若该方程有整数解,且有正整数解,则输出其正整数解的数量,所有正整数解中 x 的最小值,所有正整数解中 y的最小值,所有正整数解中 x 的最大值,以及所有正整数解中 y的最大值
若方程有整数解,但没有正整数解,你需要输出所有整数解中 x 的最小正整数值, y 的最小正整数值

解法:

用exgcd求出特解\(x_0,y_0\),该方程的通解为\(x=x_0+\frac{b}{g}t,y=y_0-\frac{a}{g}t\),求出x的最小正整数解,若此时y<=0,则方程有正整数解,否则无正整数解。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void exgcd(ll a,ll b,ll &x,ll &y){
	if(b==0) x=1,y=0;
	else{
		exgcd(b,a%b,y,x),y-=a/b*x;
	}
}
int main (){
    int T;
    scanf("%d",&T);
    while(T--){
        ll a,b,c;
        scanf("%lld%lld%lld",&a,&b,&c);
        ll g=__gcd(a,b);
        if(c%g!=0){
            printf("-1\n");
            continue;
        }
        ll x,y;
        exgcd(a,b,x,y);
        x*=c/g,y*=c/g;
        ll xmin,xmax,ymin,ymax;
        ll xadd=b/g,yadd=a/g;
        if(x<0){
            xmin=x+xadd*((-x)/xadd+1);
        }
        else{
            xmin=x-xadd*((x-1)/xadd);
        }
        if(y<0){
            ymin=y+yadd*((-y)/yadd+1);
        }
        else{
            ymin=y-yadd*((y-1)/yadd);
        }
        xmax=(c-b*ymin)/a;
        ymax=(c-a*xmin)/b;
        ll num=(xmax-xmin)/xadd+1;
        if(ymax<=0){
            printf("%lld %lld\n",xmin,ymin);
        }
        else{
            printf("%lld %lld %lld %lld %lld\n",num,xmin,ymin,xmax,ymax);
        }
    }
}
posted @ 2020-07-23 10:40  UCPRER  阅读(176)  评论(0编辑  收藏  举报