ZOJ3593(扩展欧几里得)

思路:设 D = a b s ( A − B ) D=abs(A-B) D=abs(AB),可以列出方程 a ∗ x + b ∗ y = D a*x+b*y=D ax+by=D,根据扩展欧几里得,方程有解的前提是 g c d ( a , b ) ∣ D gcd(a,b)|D gcd(a,b)D,然后题目要求的是最小,那肯定是尽可能多的组成a+b,从而使用操作三,这里举个例子:假设输入0 6 1 2,通过exgcd,得到的特解是 6 ∗ 1 + 0 ∗ 2 = 6 6*1+0*2=6 61+02=6,这里用了6次操作一,而最优的解释 2 ∗ 1 + 2 ∗ 2 = 6 2* 1+2*2=6 21+22=6,这样用2次操作三就可以了,可以用D/(a+b)求出这个中间值,在附近枚举。

int main()
{
	//freopen("in.txt", "r", stdin);
	int t;
	cin >> t;
	while (t--)
	{
		ll d1, d2, a, b;
		scanf("%lld%lld%lld%lld", &d1, &d2, &a, &b);
		ll d, x, y;
		ex_gcd(a, b, x, y, d);
		ll D = abs(d1 - d2);
		if (D%d!=0)puts("-1");
		else
		{
			x *= D / d, y *= D / d;//扩大D/d倍
			ll aa = a / d;
			ll bb = b / d;
			ll mid = D / (a + b);
			ll ans = 2e18;
			if (x > mid)
			{
				ll gp = x - mid;//离理想的差多少
				ll tmp = gp / bb;//需要几步
				f(i, tmp - 1, tmp + 1)
				{
					ll nowx = x - i * bb;
					ll nowy = y + i * aa;
					if (nowx*nowy > 0)//同向的,直接可以抵消,取最大的
						ans = min(ans, max(abs(nowx), abs(nowy)));
					else ans = min(ans, abs(nowx) + abs(nowy));//不同向
				}
			}
			else
			{
				ll gp = mid-x;//离理想的差多少
				ll tmp = gp / bb;//需要几步
				f(i, tmp - 1, tmp + 1)
				{
					ll nowx = x + i * bb;
					ll nowy = y - i * aa;
					if (nowx*nowy > 0)//同向的,直接可以抵消,取最大的
						ans = min(ans, max(abs(nowx), abs(nowy)));
					else ans = min(ans, abs(nowx) + abs(nowy));//不同向
				}
			}
			cout << ans << endl;
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值