One Person Game
题目链接:ZOJ - 3593题意:在一维地图上, 有A,B,两点, 每步只能能走a或b或a+b个单位;问最少走几步能由A到B, 若不能由A走到B输出-1;
设走x步a, y步b可以由A走到B, 则有a*x+b*y=B-A;(第三种走法a+b相当于走了相同步数的a和b)若能此方程有整数解, 则可以由A走到B, 反之不能;那么, 接下来就是求|x|+|y|的最小值;
判断方程是否有解可以通过扩展欧几里得判断, 同时也可以求出通解;
若(B-A)%gcd(a, b)==0则方程有解, 反之无解;
根据扩展欧几里得可以求得x=x+bt, y=y-at;(t为任意整数);
emmmmm~数学知识太匮乏了, 到了这就不会继续向下算了只好去搜题解;
|x|+|y|最小值在x=x+bt与y=y-at两条直线交点附近;
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;
const long long inf = 0x3f3f3f3f;
long long exgcd(long long a, long long b, long long &x, long long &y){
if(b==0){
x=1;
y=0;
return a;
}
long long r=exgcd(b, a%b, x, y);
long long t=x;
x=y;
y=t-a/b*y;
return r;
}
int main(){
int T;
cin >> T;
while(T--){
long long A, B, C;
cin >> A >> B;
long long a, b;
cin >> a >> b;
long long x, y;
long long r;
//求出a, b的最大公约数;
r=exgcd(a, b, x, y);
C=B-A;
//判断是否有解;
if(C%r) cout << -1 << endl;
else{
x*=C/r;
y*=C/r;
a/=r;
b/=r;
long long ans=inf*inf, tmp;
long long mid=(y-x)/(a+b);//mid为两条直线交点;
for(long long T=mid-1; T<=mid+1; T++){
if((x+b*T)*(y-a*T)>=0)//x, y同号, 说明向同方向走, 走x步a, y步b, 由于还可以走a+b步, 所以可以走max(x, y)步;
tmp=max(abs(x+b*T), abs(y-a*T));
else//x, y异号, 说明向相反方向走, 走了x+y步;
tmp=abs(x-y+(a+b)*T);
ans=min(ans, tmp);
}
cout << ans << endl;
}
}
return 0;
}