方程的解
[扩展欧几里德]
首先进行特判,两个小时基本想到了,除了a!=0,b==0,a*c<0这种情况
其次就是一般情况:
首先exgcd求出ax+by=GCD(a,b)的一组任意解
然后两边同乘(c/GCD)使x,y成为原方程的一组任意解,
剩下讲解见代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #define int long long 5 using namespace std; 6 const int mx=65535; 7 int read() 8 { 9 int f=1,x=0;char ch=getchar(); 10 while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} 11 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 12 return f*x; 13 } 14 int exgcd(int a,int b,int &x,int &y) 15 { 16 if(!b){x=1,y=0;return a;} 17 int d=exgcd(b,a%b,x,y); 18 int tmp=x;x=y;y=tmp-(a/b)*y; 19 return d; 20 } 21 int a,b,c; 22 int ans; 23 void work() 24 { 25 //特判出现0的情况 26 if(a==0&&b==0&&c==0){ans=mx+10;return;} 27 if(a==0&&b==0&&c!=0){ans=0;return;} 28 if(a==0||b==0) 29 { 30 if(c==0) {ans=0;return;} 31 if(a==0) swap(a,b); 32 if(a*c<0){ans=0;return;} 33 a=abs(a),c=abs(c); 34 if(c%a==0){ans=mx+10;return;} 35 else {ans=0;return;} 36 } 37 //特判ab与c异号 38 if(a>0&&b>0&&c<=0){ans=0;return;} 39 if(a<0&&b<0&&c>=0){ans=0;return;} 40 //特判a,b异号 41 int x,y; 42 int d=exgcd(a,b,x,y); 43 if(c%d){ans=0;return;} 44 if(a*b<0){ans=mx+10;return;}//注意这两行代码顺序,反例3 -3 5:应先进行上一步判定c%d!=0 45 //abc同号时,可以先处理a==b==1和a+b==c两种特殊情况,拿到部分分 46 if(a<0) a=-a,b=-b,c=-c,d=-d; 47 /* if(a==1&&b==1) 48 { 49 if(c>=2) ans=c-1; 50 else ans=0; 51 return; 52 } 53 if(a+b==c) {ans=1;return;}*/ 54 //再处理一般情况 55 ans=0; 56 x*=(c/d),y*=(c/d);//x,y成为原方程的一组特解 57 a/=d,b/=d,c/=d;//系数约分后使GCD(a,b)==1 58 x=(x%b+b)%b;//使得x成为符合条件的最小正整数,,通过+b避免负数 59 if(x==0) x+=b;//注意x为0的特殊情况 60 int ymax=(c-a*x)/b;//x最小时求出y的最大值 61 y=(y%a+a)%a; 62 if(y==0) y+=a;//同理求y的最小值 63 ans=(ymax-y)/a+1;//对于ymin->ymax之间的y,对应的x可能不是整数,所以/a成为x是整数的个数,因为包括两端,所以+1 64 return; 65 } 66 signed main() 67 { 68 int T=read(); 69 while(T--) 70 { 71 a=read(),b=read(),c=read(); 72 work(); 73 if(ans>mx) puts("ZenMeZheMeDuo"); 74 else printf("%lld ",ans); 75 } 76 }