[题解]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; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战