There is an interesting and simple one person game. Suppose there is a number axis under your feet. You are at point A at first and your aim is point B. There are 6 kinds of operations you can perform in one step. That is to go left or right by a,b and c, here c always equals to a+b.
You must arrive B as soon as possible. Please calculate the minimum number of steps.
Input
There are multiple test cases. The first line of input is an integer T(0 < T ≤ 1000) indicates the number of test cases. Then T test cases follow. Each test case is represented by a line containing four integers 4 integers A, B, a and b, separated by spaces. (-231 ≤ A, B < 231, 0 < a, b < 231)
Output
For each test case, output the minimum number of steps. If it's impossible to reach point B, output "-1" instead.
Sample Input
2 0 1 1 2 0 1 2 4
Sample Output
1 -1
题意:给你一个起点和终点,每次可以向左或向右走a步或b或c步,c=a+b;问最小步数;
根据公式ax+by=c;,当x,y同号时等于max(x,y),当a,b异号时等于(abs(x)+abs(y)),因为a,b大于0,所以不管x,y同号还是异号都是当x,y,最接近时,答案最小,写出通式
x=x1+b/(gcd)*k,y=y1-a/gcd*k; 假设x,y相等,k=(y-x)/(a+b),因为x,y不一定相等,所以枚举k附近的点
大意:一维坐标轴,有A和B两个地方,现在从A到B,每次可以向任意方向走a、b或者c的距离,其中c=a+b,问能不能走到B,能的话最少走几次。
首先可以推出这个式子:a*x+b*y+c*z=|B-A|然后又因为c=a+b,所以其实可以化成a*x+b*y=|B-A|。所以需要用扩展gcd求出x,y,但是这个x,y有可能不是最优的,为什么呢?为了让步数最小就要拉近x,y的距离,使|x-y|最小。怎么拉近,
下面来看通解方程:
x = x0 + (b/gcd)*t
y = y0 – (a/gcd)*t
实际上是关于x,y关于t的两条直线(他们必有交叉点)。
可以设x==y,然后解出那个对应的t
,得到此时的一组解(t=(y0-x0)/((a+b)/gcd))但是实际上有可能无法使x==y(没有整数t),所以算出来的t接近于交叉点的t(有可能是小数),所以可能也不是最优解,所以需要增加一次t+1,t-1,这样比较3个t得到的结果(x,y同为正或同为负时,绝对值大的那个值(c的存在,a和b合并为c),一正一负就是绝对值和),其中小的一个必是最优解。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <string> 6 #include <vector> 7 #include <stack> 8 #include <queue> 9 #include <algorithm> 10 11 #define INF 0x7fffffff 12 #define EPS 1e-12 13 #define MOD 100000007 14 #define PI 3.14159265357979823846 15 #define N 100005 16 17 using namespace std; 18 19 typedef long long ll; 20 21 ll e_gcd(ll a, ll b, ll &x, ll &y) 22 { 23 ll d = a; 24 if (b != 0) 25 { 26 d = e_gcd(b, a%b,y, x); 27 y = y - a / b * x; 28 } 29 else 30 { 31 x = 1; y = 0; 32 } 33 return d; 34 } 35 36 ll cal(ll a, ll b, ll l) 37 { 38 ll x, y; 39 ll gcd = e_gcd(a, b, x, y); 40 if (l%gcd != 0) return -1; 41 x *= l / gcd; 42 y *= l / gcd; 43 a = a / gcd; 44 b = b / gcd; 45 ll ans = ((ll)INF)*((ll)INF), f; 46 //下面来看通解方程: 47 // x = x0 + (b / gcd)*t 48 // y = y0 –(a / gcd)*t 49 // 实际上是关于x, y关于t的两条直线(他们必有交叉点)。 50 // 可以设x == y,然后解出那个对应的t 51 // , 得到此时的一组解(t = (y0 - x0) / ((a + b) / gcd)) 52 //但是实际上有可能无法使x == y(没有整数t) 53 ll mid = (y - x) / (a + b); 54 for (ll T = mid - 1; T <= mid + 1; T++) 55 { 56 // 当x, y同号时等于max(x, y),先走几步(a+b)的,再走几步单独的 57 if (abs(x + b * T) + abs(y - a * T) == abs(x + b * T + y - a * T)) 58 f = max(abs(x + b * T), abs(y - a * T)); 59 else//当a,b异号时等于(abs(x)+abs(y)) 60 f = fabs(x - y + (a + b)*T); 61 ans = min(ans, f); 62 } 63 return ans; 64 } 65 66 int main() 67 { 68 ll A, B, a, b, x, y; 69 int t; 70 cin >> t; 71 while (t--) 72 { 73 cin >> A >> B >> a >> b; 74 ll l = B - A; 75 ll ans = cal(a, b, l); 76 if (ans == -1) cout << "-1"<<endl; 77 else cout << ans << endl; 78 } 79 return 0; 80 }