1. 程式人生 > >【數論(擴充套件的歐幾里德)】ZOJ-3593-One Person Game

【數論(擴充套件的歐幾里德)】ZOJ-3593-One Person Game

#include<iostream> #include<cstdio> #include<cmath> using namespace std; #define LL long long struct euclid { LL x,y,d; }; LL labs(LL x) { if(x<0)return -x; return x; } euclid Euclid(LL a,LL b) { euclid eld1; eld1.d=a; eld1.x=1; eld1.y=0; if(!b)return eld1; euclid eld2=Euclid(b,a%b); eld1.d=eld2.d; eld1.x=eld2.y; eld1.y=eld2.x-a/b*eld2.y; return eld1; } LL cal(LL a,LL b) { LL aa=labs(a),bb=labs(b); if(a*b>0)return max(aa,bb); //當a,b同號時,就取它們絕對值之中大的那個數 return aa+bb; //異號時,就是兩個數絕對值的和 } int main() { //freopen("a.txt","r",stdin); int ca; scanf("%d",&ca); while(ca--) { LL s,t,a,b; scanf("%lld%lld%lld%lld",&s,&t,&a,&b); LL d=labs(s-t); euclid eld=Euclid(a,b); //先用擴充套件的歐幾里德判斷是否有解 if(d%eld.d) { printf("-1\n"); continue; } eld.x*=d/eld.d; eld.y*=d/eld.d; LL k,x,y,step1,step2; if(eld.x>eld.y) { k=(eld.x-eld.y)/(a/eld.d+b/eld.d); x=eld.x-k*b/eld.d; y=eld.y+k*a/eld.d; //求出當eld.x-k*(b/bel.d)=eld.y+k*(a/bel.d)的k值,因為當x==y時,x+y的值最小 step1=cal(x,y); x-=b/eld.d; y+=a/eld.d; step2=cal(x,y); //求出k值左右的兩種情況 } else { k=(eld.y-eld.x)/(a/eld.d+b/eld.d); x=eld.x+k*b/eld.d; y=eld.y-k*a/eld.d; //求出當eld.x+k*(b/bel.d)=eld.y-k*(a/bel.d)的k值 step1=cal(x,y); x+=b/eld.d; y-=a/eld.d; step2=cal(x,y); } printf("%lld\n",min(step1,step2)); } return 0; }