ZOJ 3593 One Person Game (乘法逆元)

版权声明:转载请说明出处 https://blog.csdn.net/bao___zi/article/details/81672399

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;
}

猜你喜欢

转载自blog.csdn.net/bao___zi/article/details/81672399
今日推荐