在数轴上,需要从A到B,每次可以向左或向右走
a
、
b
、
a
+
b
a、b、a+b
a、b、a+b,求最小的步数。
使用扩欧,对于
a
x
+
b
y
=
B
−
A
ax+by=B-A
ax+by=B−A的通解
x
=
x
0
+
t
∗
b
y
=
y
0
−
t
∗
b
\begin{aligned}x&=x_0+t*b \\y&=y_0-t*b\end{aligned}
xy=x0+t∗b=y0−t∗b
根据题设,答案分为两种情况:
1
、
x
、
y
同
号
,
则
答
案
为
max
(
∣
x
∣
,
∣
y
∣
)
;
2
、
x
、
y
异
号
,
答
案
为
∣
x
∣
+
∣
y
∣
.
\begin{aligned} &1、x、y同号,则答案为\max(\vert{x}\vert,\vert{y}\vert);\\&2、x、y异号,答案为\vert{x}\vert+\vert{y}\vert .\end{aligned}
1、x、y同号,则答案为max(∣x∣,∣y∣);2、x、y异号,答案为∣x∣+∣y∣.
利用基本不等式可证得,当且仅当
x
=
y
x=y
x=y时有答案最小。
故令
x
=
y
x=y
x=y,有
t
=
y
0
−
x
0
a
+
b
t=\dfrac{y_0-x_0}{a+b}
t=a+by0−x0,因为题目要求整点,所以在t的两边找答案即可。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#define inf (long long) 0x7fffffff
#define ll long long
typedef std::pair<int, int> pii;
typedef std::pair<ll, ll> pll;
typedef long long LL;
ll gcd(ll p, ll q) { return q == 0 ? p : gcd(q, p % q); }
using namespace std;
const int N = 1e6 + 10;
typedef std::pair<int, int> pii;
ll x, y;
ll Abs(ll x) { return x > 0 ? x : -x; };
ll exgcd(ll a, ll b, ll &x, ll &y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
ll r = exgcd(b, a % b, y, x);
y -= x * (a / b);
return r;
}
int main() {
ll a, b, c,A, B;
int T;
cin >> T;
while (T--) {
cin >> A >> B >> a >> b;
c = A > B ? A - B : B - A;
ll d = gcd(a, b);
if (c % d != 0) {
cout << -1 << endl;
continue;
}
a/=d;
b/=d;
exgcd(a,b,x,y);
x *= c / d;
y *= c / d;
ll t = (y - x) / (a + b);
LL ans = inf;
for (ll i = t - 1; i <= t + 1; i++) {
ll tx = x + b * i;
ll ty = y - a * i;
ll tmp;
if (Abs(tx) + Abs(ty) == Abs(tx + ty))
tmp = max(Abs(tx), Abs(ty));
else
tmp = Abs(tx) + Abs(ty);
ans = min(ans, tmp);
}
cout << ans << endl;
}
return 0;
}