关于青蛙走路问题的理解( 扩展欧几里得的应用 )

关于青蛙走路问题的理解( 扩展欧几里得的应用 )

题意是:一只青蛙在数轴的一点0处,他只可以往左跳a米或者b米,或者往右跳a米或者b米。 问这只青蛙能走到哪些点。

我们分开来看,先看这只青蛙只能往左往右走a米,得到方程:

0 + ax = want1, 这里want1是指只能走a米能到达的点, x是系数可以是任意整数。

再看这只青蛙只能往左往右走b米,得到方程:

0 + by = want2, 这里want2是指只能走b米能到达的点, y是系数可以是任意整数。

因为这只青蛙两种情况都可以走, 所以我们把上面两个公式加起来得到:

ax + by = want

这样是不是就很熟悉了,没错,根据扩展欧几里得,最终的want就是gcd(a,b)的倍数。比如gcd(a,b)=3,那么want={ ...-6,-3,0,3,6,9... };

现在扩展到青蛙跳的距离有n种方案,那么显然只要取这n个数的gcd就好了。

 

例题:

D - Jumps      Gym - 101341D

A frog lives in a one-dimensional world in the point with the coordinate 0. He needs to get to the point with the coordinate x. For some reason he cannot make jumps of arbitrary length, and can jump only by a1, ..., an in any direction. Is he able to reach x?

Input

The first line contains two integers n and x separated by a space (1 ≤ n ≤ 200000,  - 109 ≤ x ≤ 109) — the number of variants of jump length and the coordinate of the point to reach.

The second line contains n integers ai separated by spaces (1 ≤ ai ≤ 109) — the lengths of jumps the frog can make.

Output

Output «YES» (without quotes), if the frog can reach the point x, otherwise output «NO» (without quotes).

Examples Input

3 17
3 5 4

Output

YES

代码:

#include <bits/stdc++.h>

using namespace std;

int gcd( int a, int b )
{
    if ( b==0 ) {
        return a;
    }
    return gcd(b,a%b);
}

int main()
{
    int n,x,ans,u,a,b;
    cin >> n >> x;
    if ( n==1 ) {
        cin >> ans;
    }
    else {
        cin >> a >> b;
        ans = gcd(a,b);
        for ( int i=2; i<n; i++ ) {
            scanf("%d",&u);
            ans = gcd(ans,u);
        }
    }
    if ( x%ans==0 ) cout << "YES" << endl;
    else cout << "NO" << endl;

    return 0;
}

现在我们再来看一道类似的题目加深理解

C - Pagodas  HDU - 5512

题意: 从前有n座塔屹立在一条水平线上,标号1到n, 经过了一次灾难,只剩下了两座塔。有两个和尚,分别叫做 Yuwgna 和 Iaka,想让其重现佛光,便决定轮流修建古塔,其中一个人可以选择修建编号为 i的古塔,对于编号 i 应满足:设现有两古塔编号为 j 与 k ,则 i==j+k 或 i==j-k。每一座古塔不能建造两次。

视其为一个游戏,当某一个和尚不能再建造新塔时视为游戏失败,同样的,另一个和尚获得胜利。

分析:为了方便理解我们让a=4,b=6, n = 125 。

首先我们定义仅存的两座塔标号为a和b, 我们分开来看:

1. 让a作为j,b作为k, 我们能修的塔的编号为want,得到公式

4 + 6x = want,式中x是整数, 那么want = { ...-8,-2,4,10,16,22... } ,因为标号1~n, 自动把负数去掉。

2. 让b作为j,a作为k, 我们能修的塔的编号为want,得到公式

4y + 6 = want ,式中y是整数, 那么want = { ...-6,-2,2,6,10,14... } ,因为标号1~n, 自动把负数去掉。

这样两式相加得: 6(x+1) + 4(y+1) = want , 还是 6x + 4y = want = gcd(a,b), 这样我们能修复的点就是want值,也就是gcd(a,b)的倍数。

 

Input

第一行输入一个数 t (1<= t <= 500) 代表着将要测试的样例数。
对于每一个例子,第一行输入一个 n (2<= n<= 20000) 并且跟着两个数 a 和 b。

Output

对于每一个例子,输出胜者 (``Yuwgna" 或 ``Iaka”)。假设他们每次都会做出最佳决定。

Sample Input

16
2 1 2
3 1 3
67 1 2
100 1 2
8 6 8
9 6 8
10 6 8
11 6 8
12 6 8
13 6 8
14 6 8
15 6 8
16 6 8
1314 6 8
1994 1 13
1994 7 12

Sample Output

Case #1: Iaka
Case #2: Yuwgna
Case #3: Yuwgna
Case #4: Iaka
Case #5: Iaka
Case #6: Iaka
Case #7: Yuwgna
Case #8: Yuwgna
Case #9: Iaka
Case #10: Iaka
Case #11: Yuwgna
Case #12: Yuwgna
Case #13: Iaka
Case #14: Yuwgna
Case #15: Iaka
Case #16: Iaka

代码:

#include <iostream>

using namespace std;

int gcd( int a, int b )
{
    if ( b==0 ) {
        return a;
    }
    return gcd(b,a%b);
}

int main()
{
    int ji=1,n,listt,a,b;
    cin >> listt;
    while ( listt-- ) {
        cin >> n >> a >> b;
        int ans = n/gcd(a,b);
        cout << "Case #" << ji++ << ": ";
        if ( ans%2==0 ) {
            cout << "Iaka" << endl;
        }
        else {
            cout << "Yuwgna" << endl;
        }
    }

    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值