ZOJ-3593 One Person Game(数论-扩展欧几里得)

题意

给一个起点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=(x0'+y0')/(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;
}

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/85018423
今日推荐