UVALive 6428 A+B // 扩展欧几里德

Problem Description

There is a computer, which has two memory cells (let us denote these cells by the letters a and b). Each cell (variable) stores some integer at any time. The computer can execute only two instructions a+=b and b+=a. The first instruction increases the value of the variable a by the value stored in the variable b. The second one, respectively, increases the value of b by the value a. A program for this computer consists of a sequence (possible empty) of such instructions. The instructions are executed in the appropriate order. Your task is to determine whether the given value S can be obtained in some cell after executing some program.

Input

The input file contains several test cases, each of them as described below.
The input contains three integers: the initial value of the variable a, the initial value of the variableb and the required value S (0 ≤ a, b, S ≤ 10^18).

Output

For each test case, write to the output ‘YES’ if the required value can be obtained as a result of some program execution, or ‘NO’ otherwise on a line by itself.

Sample Input

1 2 3
3 4 5
3 4 17

Sample Output

YES
NO
YES

解题思路

判断 ax+by=s ……(1)是否存在非负整数解, 且满足 gcd(x,y)=1

根据扩展欧几里得算法知,存在整数(x, y) 满足 ax+by=gcd(a,b) ;
因此我们可以先根据 【gcd(a, b) 能否整除 s】 来判断 是否存在 整数解。

引理:设 a,b,c 为任意整数。若方程 ax+by=c 的一组整数解为 (x0,y0) ,则它的任意整数解都可以写成 (x0+kb,y0ka) , 其中 a=a/gcd(a,b),b=b/gcd(a,b)

d=gcd(a,b);
(1)式 转化为 ax+by=s ……(2)
其中 a=a/d,b=b/d,s=s/d;
然后求出一组 x,y 满足 ax+by=1 ……(3);
这个算出的 x,y 要乘上 s 才是和 (2)式等价 即 x=s,y=s;
然后根据 x 找到最小非负整数解 x0 , 根据引理,只要 x %= b ,若为负数,则加 b 至非负为止。
最后枚举所有xy即可。

参考代码

#include <stdio.h>
typedef long long ll;
//扩展欧几里得算法 : 求解满足ax+by=1的一组解,且d = gcd(a, b);
void exgcd(ll a, ll b, ll& d, ll& x, ll& y) {
    if (!b) {
        d = a; x = 1; y = 0;
    } else {
        exgcd(b, a % b, d, y, x);
        y -= x * (a / b);
    }
}
ll gcd(ll a, ll b){return b ? gcd(b, a % b) : a;}
ll a, b, s, d, x, y;
void work() {
    // 特判有0的情况
    if (a == 0) {
        if (b == 0) printf("%s\n", s ? "NO" : "YES");
        else printf("%s\n", s % b ? "NO" : "YES");
        return ;
    } else if (b == 0) {
        printf("%s\n", s % a ? "NO" : "YES");
        return ;
    }
    exgcd(a, b, d, x, y);
    if (s % d) {
        puts("NO");
        return ;
    }
    a /= d; b /= d; s /= d;
    x *= s % b; x %= b;
    while (x < 0) x += b;
    y = (s - a * x) / b;
    while (y >= 0) {
        if (gcd(x, y) == 1) {
            puts("YES");
            return ;
        }
        x += b; y -= a;
    }
    puts("NO");
}
int main() {
    while (~scanf("%lld %lld %lld", &a, &b, &s))  work();
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值