方程的解
[扩展欧几里德]
首先进行特判,两个小时基本想到了,除了a!=0,b==0,a*c<0这种情况
其次就是一般情况:
首先exgcd求出ax+by=GCD(a,b)的一组任意解
然后两边同乘(c/GCD)使x,y成为原方程的一组任意解,
剩下讲解见代码
#include<iostream>
#include<cstdio>
#include<cmath>
#define int long long
using namespace std;
const int mx=;
int read()
{
int f=,x=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')f=-;ch=getchar();}
while(ch<=''&&ch>=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return f*x;
}
int exgcd(int a,int b,int &x,int &y)
{
if(!b){x=,y=;return a;}
int d=exgcd(b,a%b,x,y);
int tmp=x;x=y;y=tmp-(a/b)*y;
return d;
}
int a,b,c;
int ans;
void work()
{
//特判出现0的情况
if(a==&&b==&&c==){ans=mx+;return;}
if(a==&&b==&&c!=){ans=;return;}
if(a==||b==)
{
if(c==) {ans=;return;}
if(a==) swap(a,b);
if(a*c<){ans=;return;}
a=abs(a),c=abs(c);
if(c%a==){ans=mx+;return;}
else {ans=;return;}
}
//特判ab与c异号
if(a>&&b>&&c<=){ans=;return;}
if(a<&&b<&&c>=){ans=;return;}
//特判a,b异号
int x,y;
int d=exgcd(a,b,x,y);
if(c%d){ans=;return;}
if(a*b<){ans=mx+;return;}//注意这两行代码顺序,反例3 -3 5:应先进行上一步判定c%d!=0
//abc同号时,可以先处理a==b==1和a+b==c两种特殊情况,拿到部分分
if(a<) a=-a,b=-b,c=-c,d=-d;
/* if(a==1&&b==1)
{
if(c>=2) ans=c-1;
else ans=0;
return;
}
if(a+b==c) {ans=1;return;}*/
//再处理一般情况
ans=;
x*=(c/d),y*=(c/d);//x,y成为原方程的一组特解
a/=d,b/=d,c/=d;//系数约分后使GCD(a,b)==1
x=(x%b+b)%b;//使得x成为符合条件的最小正整数,,通过+b避免负数
if(x==) x+=b;//注意x为0的特殊情况
int ymax=(c-a*x)/b;//x最小时求出y的最大值
y=(y%a+a)%a;
if(y==) y+=a;//同理求y的最小值
ans=(ymax-y)/a+;//对于ymin->ymax之间的y,对应的x可能不是整数,所以/a成为x是整数的个数,因为包括两端,所以+1
return;
}
signed main()
{
int T=read();
while(T--)
{
a=read(),b=read(),c=read();
work();
if(ans>mx) puts("ZenMeZheMeDuo");
else printf("%lld\n",ans);
}
}