【Codeforces】1612D X-Magic Pair 题解

题目大意

给定三个正整数 a , b , x ( 1 ≤ a , b , x ≤ 1 0 18 ) a,b,x(1 \le a,b,x \le 10^{18}) a,b,x(1a,b,x1018),可以对 a , b a, b a,b进行两种操作:*

  • a = ∣ a − b ∣ a = |a - b| a=ab
  • b = ∣ a − b ∣ b = |a - b| b=ab

问是否可以通过任意次这两种操作使得 a = x a = x a=x或者 b = x b = x b=x

题目链接

思路

假设 a < b a < b a<b,我们推一下 ( a , b ) (a,b) (a,b)可以有哪些变化,我们要尽量的用有规律的方式去枚举出所有可能变化

  1. ( a , b ) ⇔ ( b − a , b ) (a, b) \Leftrightarrow (b - a, b) (a,b)(ba,b),然后就无法继续产生新变化了。
  2. ( a , b ) ⇒ ( a , b − a ) (a, b) \Rightarrow (a, b - a) (a,b)(a,ba)。那么接下来有两种变化:
    • 2.1: a > b − a 。 ( a , b − a ) ⇒ ( 2 a − b , b − a ) a > b - a。 (a, b - a) \Rightarrow (2a - b, b - a) a>ba(a,ba)(2ab,ba) ,可继续产生新变化。
      ( a , b − a ) ⇔ ( a , 2 a − b ) (a, b - a) \Leftrightarrow (a, 2a - b) (a,ba)(a,2ab),无法继续产生新变化变化。
    • 2.2: a < b − a 。 ( a , b − a ) ⇒ ( a , b − 2 a ) a < b - a。 (a, b - a) \Rightarrow (a, b - 2a) a<ba(a,ba)(a,b2a) 可继续产生新变化。#
      ( a , b − a ) ⇔ ( b − 2 a , b − a ) (a, b - a) \Leftrightarrow (b - 2a, b - a) (a,ba)(b2a,ba) 无法继续产生新变化变化。

通过这种方式,我们就能不断地去枚举出所有可能达到的数,但是如果一步一步地去做,那么会超时。

对于2.2#的那一步,假设 b ′ = b − c ∗ a b' = b - c*a b=bca,那么显然当 a < b − c ∗ a a < b - c * a a<bca时,会一直执行该操作。而选择2.2的另外一步骤,也不会产生新的数,所以我们可以直接跳过这个步骤直接让 ( a , b − a ) ⇒ ( a , b % a ) (a, b - a) \Rightarrow (a, b\%a) (a,ba)(a,b%a),并检验一下是否会产生了答案,即判断 ( b − x ) % a = = 0 ? (b - x) \% a == 0 ? (bx)%a==0?

#include <cstdio>
#include <iostream>
using namespace std;

int T;
long long a, b, x;

int main()
{
    scanf("%d", &T);
    while(T--) {
        bool succ = false;
        scanf("%lld%lld%lld", &a, &b, &x);
        while(a && b) {
            if(a > b)
                swap(a, b);
            a = min(a, b - a); //确保 a < b - a (其实本质上就是简略了步骤1)
            if(a == x || b == x) {
                succ = true;
                break;
            }
            if(x > b || (x < b && x > b - a) || a == 0)
                break;
            if((b - x) % a == 0) {
                succ = true;
                break;
            }
            b %= a;
        }
        if(succ)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值