[题解]P5656 【模板】二元一次不定方程 (exgcd)

P5656 【模板】二元一次不定方程 (exgcd)

若存在\(ax+by=c\),则可以根据特解\(x,y\)求出任意通解\(x',y'\)
\(\begin{cases} x'=x+k*\frac{b}{\gcd(a,b)}\\ y'=y-k*\frac{a}{\gcd(a,b)} \end{cases}(k\in \mathbb{Z})\)

求特解的方法是「扩展欧几里得(exgcd)」,如果没接触过可以先阅读此文或搜索更多信息。

该方程有整数解当且仅当\(\gcd(a,b)|c\)。所以不满足直接输出-1

接下来考虑怎么求通解。

首先,exgcd求出来的结果是\(ax+by=\gcd(a,b)\),我们要满足\(ax+by=c\),必须先把\(x,y\)都乘\(\frac{c}{\gcd(a,b)}\)

然后,我们知道\(k\)有一个取值范围,这个范围内每个\(k\)都对应一组解。我们只需要算出\(x',y'>0\)\(k\)的取值范围,一切就好弄了。

\(\frac{b}{\gcd(a,b)}=r,\frac{a}{\gcd(a,b)}=s\)。则:

  • \(x'>0\iff x+kr>0\iff k>-\frac{x}{r}\),故\(k\)的最小值\(mink=\lfloor -\frac{x}{r}\rfloor+1\)
  • \(y'>0\iff y-ks>0\iff k<\frac{y}{s}\),故\(k\)的最大值\(maxk=\lceil \frac{y}{s}\rceil-1\)

如果\(mink>maxk\),说明有整数解但没有正整数解,输出\(2\)个值:

  • \(x\)最小值:\(x+mink*r\)
  • \(y\)最小值:\(y-maxk*s\)

否则说明有整数解,需要输出\(5\)个值:

  • 个数:\(maxk-mink+1\)
  • \(x\)最小值:\(x+mink*r\)
  • \(y\)最小值:\(y-maxk*s\)
  • \(x\)最大值:\(x+maxk*r\)
  • \(y\)最大值:\(y-mink*s\)

注意:开long long

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,a,b,c;
int exgcd(int a,int b,int& x,int& y){
	int d;
	if(b==0) x=1,y=0,d=a;
	else d=exgcd(b,a%b,y,x),y-=a/b*x;
	return d;
}
signed main(){
	cin>>t;
	int x,y;
	while(t--){
		cin>>a>>b>>c;
		int gcd=exgcd(a,b,x,y);
		if(c%gcd!=0){
			cout<<"-1\n";
			continue;
		}
		int stepx=b/gcd,stepy=a/gcd;
		x*=c/gcd,y*=c/gcd;
		int mink=floor(-1.0*x/stepx)+1,maxk=ceil(1.0*y/stepy)-1;
		if(mink>maxk){
			cout<<x+mink*stepx<<" "<<y-maxk*stepy<<"\n";
		}else{
			cout<<maxk-mink+1<<" ";
			cout<<x+mink*stepx<<" "<<y-maxk*stepy<<" ";
			cout<<x+maxk*stepx<<" "<<y-mink*stepy<<"\n";
		}
	}
	return 0;
}
posted @ 2024-04-25 22:08  Sinktank  阅读(50)  评论(0编辑  收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2024 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.