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;
}