P5656 【模板】exgcd

謝謝你。

對於一個二元一次的方程式 \(ax+by=c\),顯然當且僅當 \(c\)\(gcd(a,b)\) 的倍數時,該方程有解。

在之前,我們用 \(exgcd\) 找到了一組特解 \(x,y\),而顯然通解是 \(a(x+db)+b(y-da)=c\)(消完之後就是原方程式)。

我們需要整數解,所以考慮使 \(db\)\(da\) 都用最小的方式表示通解,顯然黨 \(d=gcd(a,b)\)時, \(db\)\(da\) 都是最小的,設其分別為 \(d_x\)\(d_y\)

於是通解可以表示成:

\[X=x+sd_x \]

\[Y=y-sd_y \]

\(X>0\),有 \(s> \large \frac{-x}{d_x}\)

\(Y>0\),有 \(s< \large \frac{y}{d_y}\)

又因爲需要正整數解,所以我們有:

\[\large\lceil_{\frac{-x+1}{d_x}}\rceil \le s \le \lfloor_{\frac{y-1}{d_y}}\rfloor \]

若沒有正整數解,即\(s\)不在上下界範圍之内,求\(x\)的最小正整數解要代入\(\frac{-x+1}{d_x}\),求\(y\)的最小正整數解則要代入\(\frac{y-1}{d_y}\)

若存在正整數解,已知上下界可以求出正整數解的個數,求\(x\)\(y\)的最大小值直接代入特定的\(s\)即可(例如,求\(x\)的最大值,\(s\)要取到上界,此時\(y\)有最小值,反之同理)。

代碼:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=210000;
int T,X,Y;
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') w=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=(s<<1)+(s<<3)+(ch^48);
		ch=getchar();
	}
	return s*w;
}
int exgcd(int a,int b,int &x,int &y){
	if(!b){
		x=1;
		y=0;
		return a;
	}
	int r=exgcd(b,a%b,x,y);
	int tmp=x;
	x=y;
	y=tmp-a/b*y;
	return r;
}
inline int gcd(int a,int b){
	return b?gcd(b,a%b):a;
}
inline void solve(){
	int A=read(),B=read(),C=read();
	if(C%gcd(A,B)!=0){
		printf("-1\n");return;
	}
	int d=exgcd(A,B,X,Y);
	int dx=B/d,dy=A/d;
	X=X*C/d;Y=Y*C/d;
	int xxoo=ceil((1.0-X)/dx),ooxx=floor((Y-1.0)/dy);
	if(xxoo>ooxx){
		printf("%lld %lld\n",X+xxoo*dx,Y-ooxx*dy);
	}else{
		printf("%lld ",ooxx-xxoo+1);
		printf("%lld %lld %lld %lld\n",X+xxoo*dx,Y-ooxx*dy,X+ooxx*dx,Y-xxoo*dy);
	}
} 
signed main(){
	T=read();
	while(T--) solve();
	return 0;
} 
posted @ 2022-07-27 16:38  Broken_Eclipse  阅读(100)  评论(0编辑  收藏  举报

Loading