ZOJ 3593 One Person Game (乘法逆元)

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. (-2^31 ≤ A, B < 2^31, 0 < a, b < 2^31)

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 ,他可以向左或者向右  走,一步能走a,b,a+b,求從A到達B的最小步數。

解題思路: 首先L=fabs(B-A)爲我們需要前進的距離,那麼題目就能轉化爲

ax+by=L

ax+(a+b)y=L

bx+(a+b)y=L

然後我們可以歸結爲只需要求ax+by=L

先用擴展gcd求乘法逆元,求得一組x,y後,求最小的特解x0,y0

x0=x*L/gcd(a,b) y0=y*L/gcd(a,b)

令am=a/gcd,bm=b/gcd,則通解可表示爲(x0+k*bm, y0-k*am)。

然後通解可以表示爲x=x0+bmt,y=y0−amt
可以在座標系上畫出兩條直線l1,l2(注意上式中的x不同於座標系的x軸,x軸準確的說應該是t軸!),並且斜率是一正一負(a,b同正,題目已說)
所以呢,取一個t,如果x和y異號,答案就是你畫一條平行於y軸的直線,它和l1,l2的交點間的距離。如果同號就是在這兩條直線上橫座標爲t的離x軸遠的那個點離x軸的距離,那麼意會可得,l1,l2交點處取到最優解,由於交點處的t不一定是整數,所以我們要做一些處理(見代碼)

 

/*************************************************************************
	> File Name:  zoj3593.cpp
	> Author: baozi
	> Last modified: 2018年08月14日 星期二 18時39分
	> status:AC 
 ************************************************************************/
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
using namespace std;
#define ll long long 
ll a,b,A,B,C,c,t1,t2,t3;
ll ex_gcd(ll a,ll b,ll &x,ll &y){
	if(!b){
		x=1,y=0;
		return a;
	}
	ll gc=ex_gcd(b,a%b,x,y);
	ll temp=x;
	x=y;
	y=temp-a/b*y;
	return gc;
}
ll cal(ll a,ll m, ll c){
	ll x,y;
	ll gc=ex_gcd(a,b,x,y);
	if(c%gc!=0) return -1;
	x*=c/gc;
	y*=c/gc;
	a/=gc;b/=gc;
	ll mid=(y-x)/(a+b);
	ll ans=fabs(x)+fabs(y),k1;
	for(int i=mid-1;i<=mid+1;i++){
		if(fabs(x+b*i)+fabs(y-a*i)==fabs(x+y+b*i-a*i)){
			k1=max(x+b*i,y-a*i);
		}	
		else k1=fabs(x-y+(a+b)*i);
		ans=min(ans,k1);
	}
	return ans;
}
int main(){
	int i,j,t;
	scanf("%d",&t);
	while(t--){
		scanf("%lld%lld%lld%lld",&A,&B,&a,&b);
		C=fabs(B-A);c=a+b;
		t1=cal(a,b,C);
		if(t1==-1){
			printf("-1\n");
			continue;
		}
		ll ans=t1;
		printf("%lld\n",ans); 
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章