P5656 【模板】二元一次不定方程 (exgcd)
整理一下关于 exgcd 的内容,都说写完这道题就会做所有 exgcd 的题了,是不是我不知道,反正今天又做了一遍,记录一下我的过程,感觉没有太难。
题意
求不定方程 \(ax+by=c\) 的解。
以下称正整数解为 \(x,y\) 都是正整数的解,其中有一个是非正整数就不行。
如果没有任何整数解,输出 -1。
如果有正整数解,输出个数,x_min,y_min,x_max,y_max。
如果没有正整数解,输出 x 正整数解的 x_min,y 正整数解的 y_min。
接下来分三步进行:求出基本量,处理情况二,处理情况三。
求出基本量
先把无解判了:\(c\% gcd(a,b)\ne 0\),裴蜀定理,没啥好说的。
之后使用 exgcd 求出一组特殊解 \(x_0\), \(y_0\)。
不定方程的解我们就可以刻画出来了。
\(x'=x_0+\frac{b}{gcd(a,b)}\times t\)
\(y'=y_0-\frac{a}{gcd(a,b)}\times t\)
根据我的习惯,我将称呼 \(\frac{b}{gcd(a,b)}\) 为 \(lenx\),\(\frac{a}{gcd(a,b)}\) 为 \(leny\),因为这个就像是一块一块的长度,方便接下来的推导。
如果想要知道 \(x,y\) 的极值情况明显就可以利用 \(t\) 了。
我们求出来 \(t_{min}\) 和 \(t_{max}\),利用 \(x,y\) 是正整数解的性质列出来两个式子。
不难求出来,懒得写了,注意上下取整问题。
直接判断 \(t_{min}\) 是不是大于 \(t_{max}\) 就行,如果是就是情况二。
情况二&&情况三
情况二:
经典问题,根据通解的式子可以得出一个变量的最小非负整数解,特判一下 0 就行了。
情况三:
数量就是 \(t_{max}-t_{min}+1\),按照通解式子搞就行。
代码
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int Exgcd(int a, int b, int &x, int &y){
if(!b){x=1; y=0; return a;}
int d=Exgcd(b,a%b,y,x);
y-=(a/b)*x; return d;
}
int Gcd(int a, int b){
if(!b) return a;
return Gcd(b,a%b);
}
void Solve(int a, int b, int c){
int d=Gcd(a,b);
if(c%d){cout<<-1<<'\n'; return;}//type 1
int x_gcd, y_gcd, x_0, y_0;
Exgcd(a,b,x_gcd,y_gcd);
x_0=x_gcd*c/d; y_0=y_gcd*c/d;
int lenx=b/d, leny=a/d;
int t_min, t_max;
t_min=ceil((double)1.0*(-x_0+1)/lenx);
t_max=floor((double)1.0*(y_0-1)/leny);
if(t_min>t_max){//type 3
int x_min, y_min;
x_min=(x_0%lenx+lenx)%lenx;
y_min=(y_0%leny+leny)%leny;
if(x_min==0) x_min=lenx;
if(y_min==0) y_min=leny;
cout<<x_min<<" "<<y_min<<'\n';
}else{//type2
cout<<t_max-t_min+1<<" ";
cout<<x_0+lenx*t_min<<" ";
cout<<y_0-leny*t_max<<" ";
cout<<x_0+lenx*t_max<<" ";
cout<<y_0-leny*t_min<<'\n';
}
return;
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T; cin>>T; while(T--){
int a, b, c;
cin>>a>>b>>c;
Solve(a,b,c);
}
return 0;
}

浙公网安备 33010602011771号