题意
给一个起点A,一个终点B,
从起点出发,
每次可以选择向左或向右走a格,b格,或c格(c=a+b),
走一次记为一步,求A到B的最小步数,无法走到输入-1
思路来源
https://blog.csdn.net/yjf3151731373/article/details/70071941
题解
最后肯定是求ax+by=d,d=abs(B-A)
当d不能整除c=gcd(a,b)时,显然为-1,
令a/=c,b/=c,d/=c,等价于求a'x+b'y=d',gcd(a',b')=1
此时可用a'x+b'y=1求一组解x0,y0,
x0*=d,y0*=d即为一组原方程解x0',y0'
而原方程通解x=x0'+k*b',y=y0'-k*a',
当x与y同号时,答案为max(|x|,|y|);
当x与y异号时,答案为|x|+|y|;
显然,若x==y能成立,则任何其它解x1,y1都会增大其中一个的绝对值从而使答案更大,
所以如果x==y能成立,答案就是x==y,
此时有x0'+k*b'=y0'-k*a',k=(y0'-x0')/(a'+b')。
这就是一个凹函数,x==y的时候是拐点,
如果k是double的话,一定是取拐点,此时有极小值|x|步
其它情况下,不妨x<y,
若x与y距离不是最小(即存在x1,y1,使得x<x1<y1<y成立时),
x1和y1这组解,无论是同号还是异号,都比x、y这组解更优。
但同样也有可能,x,y距离是当前最小了(但不是0)(却存在x1,y1,使得x<y1<y<x1)
而x1,y1这组解更优,这其实是k无法取整从而使距离不能取到理论最小导致的。
若不能取拐点的话,离拐点最近的两个整点,都判一下就好了
k无法取整值,所以就要取距k最近的那两个整值判断一下哪个更小,
那就不妨直接枚举k-1,k,k+1,取最小
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
const int maxn=3e3+10;
using namespace std;
typedef long long ll;
int t;
ll A,B,a,b;
ll extgcd(ll a,ll b,ll &x,ll &y)
{
ll d=a;
if(b)d=extgcd(b,a%b,y,x),y-=(a/b)*x;
else x=1,y=0;
return d;
}
int main()
{
scanf("%d",&t);
while(t--)
{
ll c,d,x,y,ans=1e18;
scanf("%lld%lld%lld%lld",&A,&B,&a,&b);
d=extgcd(a,b,x,y);
if(A<B)swap(A,B);c=A-B;
if(c%d)
{
puts("-1");
continue;
}
else
{
x*=(c/d);y*=(c/d);
a/=d;b/=d;
//a'x+b'y=c' (x,y)一组特解
ll k=(y-x)/(a+b);
for(ll i=k-1;i<=k+1;++i)
{
ll xx=x+b*i,yy=y-a*i,xxx=abs(xx),yyy=abs(yy);
if(xx*yy>0)ans=min(ans,max(xxx,yyy));
else ans=min(ans,xxx+yyy);
}
printf("%lld\n",ans);
}
}
return 0;
}