P5656 【模板】二元一次不定方程 (exgcd)
P5656 【模板】二元一次不定方程 (exgcd)
题目描述
给定不定方程
若该方程无整数解,输出
若该方程有整数解,且有正整数解,则输出其正整数解的数量,所有正整数解中
若方程有整数解,但没有正整数解,你需要输出所有整数解中
正整数解即为
整数解即为
输入格式
第一行一个正整数
接下来
输出格式
若该行对应的询问无整数解,一个数字
若该行对应的询问有整数解但无正整数解,包含
否则包含
【数据范围】
对于
说句闲话:
曾经励志永不学数论的我竟然为了写 excrt 来把这题补了qwq
说好的数据结构选手呢?(ノ▼Д▼)ノ
Solution:
exgxd基础:
对于一个不定方程
其有解的充要条件其实就是
我们思考一下为什么:
首先我们不难发现
所以我们可以用exgcd轻易的构造出
那么就能得到原方程的特解:
既
然后我们考虑构造通解:
然后我们考虑最大/最小化通解
然后你在感性理解一下x,y的关系应该是 "此消彼长"
的,那么当
然后我们已经求出了
回顾一下我们的通解:
所以我们只需要设
然后解的个数的话就是
Code:
#include<bits/stdc++.h> #define ll long long using namespace std; ll read() { ll res=0,flag=0; char c=getchar(); while(c<'0'||'9'<c){if(c=='-')flag=1;c=getchar();} while('0'<=c&&c<='9'){res=(res<<3)+(res<<1)+c-'0';c=getchar();} return (flag ? -res : res); } ll exgcd(ll &x,ll &y,ll a,ll b) { if(b==0) { x=1,y=0;return a; } ll res=exgcd(y,x,b,a%b); y-=a/b*x; return res; } ll a,b,c,x,y; void work() { a=read(),b=read(),c=read(); ll d=exgcd(x,y,a,b),q=c/d; if(c%d){printf("%d\n",-1);return;} x*=q,y*=q; ll tx=b/d,ty=a/d,k=ceil((1.0-x)/tx); x+=tx*k,y-=ty*k; if(y<=0) { ll ymin=y+ty*1ll*ceil((1.0-y)/ty); printf("%lld %lld\n",x,ymin); return; } ll tmp=(y-1)/ty; printf("%lld ",tmp+1); printf("%lld %lld ",x,y-tmp*ty); printf("%lld %lld\n",x+tmp*tx,y); } int main() { //freopen("exgcd.in","r",stdin); //freopen("exgcd.out","w",stdout); int T; cin>>T; while(T--)work(); return 0; }