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;
}
posted @ 2025-10-29 11:21  BaiBaiShaFeng  阅读(3)  评论(0)    收藏  举报
Sakana Widget右下角定位