令c = a+b, d = A-B,則等價於求{|x|+|y| | ax+by=d || ax+cy=d || bx+cy=d}。對於ax+by=d,用擴展歐幾里得算法求得axx+byy=gcd(a,b),是否有解可由d是否爲gcd的倍數判斷。若有解,原方程的一組解爲(x0, y0) = (xx*d/gcd, yy*d/gcd)。令aa=a/gcd,bb=b/gcd,則通解可表示爲(x0+k*bb, y0-k*aa)。能使|x|+|y|最小的整點一定是最靠近直線與座標軸交點的地方,可以由|x|+|y|=C的圖像不斷平移看出。由於負數取整時是先對它的絕對值取整,再添上負號,所以考慮的範圍要是[-x0/bb-1, -x0/bb+1], [y0/aa-1, y0/aa+1]。
#include <cstdio>
#define ll long long
inline void Min(ll& x, ll y)
{
if(x < 0) x = y;
if(y < 0) return;
if(y < x) x = y;
}
inline ll Abs(ll x)
{
return x<0?-x:x;
}
inline ll Sum(ll x, ll y)
{
return Abs(x)+Abs(y);
}
ll exgcd(ll a,ll b,ll& x,ll& y)
{
ll t, ret;
if (! b)
{
x=1, y=0;
return a;
}
ret = exgcd(b, a%b, x, y);
t = x, x = y, y = t - a/b*y;
return ret;
}
ll a, b, c, d, A, B, T;
ll x, y, gcd, k, min, sum;
ll solve(ll a, ll b)
{
gcd = exgcd(a, b, x, y);
if(d%gcd != 0)
return -1;
x = x*(d/gcd);
y = y*(d/gcd);
a /= gcd;
b /= gcd;
min = Sum(x, y);
k = -x/b-1;
sum = Abs(x+k*b)+Abs(y-k*a);
Min(min, sum);
k += 1;
sum = Abs(x+k*b)+Abs(y-k*a);
Min(min, sum);
k += 1;
sum = Abs(x+k*b)+Abs(y-k*a);
Min(min, sum);
k = y/a-1;
sum = Abs(x+k*b)+Abs(y-k*a);
Min(min, sum);
k += 1;
sum = Abs(x+k*b)+Abs(y-k*a);
Min(min, sum);
k += 1;
sum = Abs(x+k*b)+Abs(y-k*a);
Min(min, sum);
return min;
}
int main()
{
scanf("%lld", &T);
while(T --)
{
scanf("%lld%lld%lld%lld", &A, &B, &a, &b);
if(A == B)
{
printf("0\n");
continue;
}
c = a + b;
d = Abs(A - B);
B = solve(a, b);
Min(B, solve(a, c));
Min(B, solve(b, c));
printf("%lld\n", B);
}
return 0;
}