思路:设 D = a b s ( A − B ) D=abs(A-B) D=abs(A−B),可以列出方程 a ∗ x + b ∗ y = D a*x+b*y=D a∗x+b∗y=D,根据扩展欧几里得,方程有解的前提是 g c d ( a , b ) ∣ D gcd(a,b)|D gcd(a,b)∣D,然后题目要求的是最小,那肯定是尽可能多的组成a+b,从而使用操作三,这里举个例子:假设输入0 6 1 2,通过exgcd,得到的特解是 6 ∗ 1 + 0 ∗ 2 = 6 6*1+0*2=6 6∗1+0∗2=6,这里用了6次操作一,而最优的解释 2 ∗ 1 + 2 ∗ 2 = 6 2* 1+2*2=6 2∗1+2∗2=6,这样用2次操作三就可以了,可以用D/(a+b)求出这个中间值,在附近枚举。
int main()
{
//freopen("in.txt", "r", stdin);
int t;
cin >> t;
while (t--)
{
ll d1, d2, a, b;
scanf("%lld%lld%lld%lld", &d1, &d2, &a, &b);
ll d, x, y;
ex_gcd(a, b, x, y, d);
ll D = abs(d1 - d2);
if (D%d!=0)puts("-1");
else
{
x *= D / d, y *= D / d;//扩大D/d倍
ll aa = a / d;
ll bb = b / d;
ll mid = D / (a + b);
ll ans = 2e18;
if (x > mid)
{
ll gp = x - mid;//离理想的差多少
ll tmp = gp / bb;//需要几步
f(i, tmp - 1, tmp + 1)
{
ll nowx = x - i * bb;
ll nowy = y + i * aa;
if (nowx*nowy > 0)//同向的,直接可以抵消,取最大的
ans = min(ans, max(abs(nowx), abs(nowy)));
else ans = min(ans, abs(nowx) + abs(nowy));//不同向
}
}
else
{
ll gp = mid-x;//离理想的差多少
ll tmp = gp / bb;//需要几步
f(i, tmp - 1, tmp + 1)
{
ll nowx = x + i * bb;
ll nowy = y - i * aa;
if (nowx*nowy > 0)//同向的,直接可以抵消,取最大的
ans = min(ans, max(abs(nowx), abs(nowy)));
else ans = min(ans, abs(nowx) + abs(nowy));//不同向
}
}
cout << ans << endl;
}
}
return 0;
}