HDU5584-LCM Walk(数论,数学推导)

题目链接:HDU5584

题目意思:

你是一只青蛙,你在一个无限大的二维平面,如果你当前的位置为(x,y),那么你可以跳到(x +LCM(x,y),y)或者(x, y + LCM(x,y))。现在给你终点(ex,ey), 问有多少个起点可以按照这种走法走到这个点。

题目思路:

x = n ∗ k , y = m ∗ k , g c d ( x , y ) = k x = n * k,y = m * k,gcd(x,y) = k x=nky=mkgcd(xy)=k,也就是说 g c d ( n , m ) = 1 gcd(n, m) = 1 gcd(n,m)=1
那么我们可以得到 L C M ( x , y ) = x ∗ y / k = n ∗ k ∗ m ∗ k / k = n ∗ m ∗ k LCM(x,y) = x * y / k = n * k * m * k / k = n * m * k LCM(xy)=xy/k=nkmk/k=nmk
( x , y ) 可 以 表 示 为 ( n ∗ k , m ∗ k ) (x,y)可以表示为(n * k ,m * k) xy)nkmk),他可以去 ( n ∗ ( m + 1 ) ∗ k , m ∗ k ) (n * (m + 1) * k , m * k) (n(m+1)k,mk)或者 ( n ∗ k , ( n + 1 ) ∗ m ∗ k ) (n * k , (n + 1) * m * k) (nk,(n+1)mk)
我们发现 g c d ( n ∗ ( m + 1 ) ∗ k , m ∗ k ) = g c d ( n ∗ k , ( n + 1 ) ∗ m ∗ k ) = k gcd(n * (m + 1) * k , m * k) = gcd (n * k , (n + 1) * m * k) = k gcd(n(m+1)k,mk)=gcd(nk,(n+1)mk)=k
因为 g c d ( n , m ) = 1 , g c d ( n , n + 1 ) = 1 , g c d ( m , m + 1 ) = 1 gcd(n,m) = 1,gcd(n,n + 1) = 1,gcd(m,m + 1) = 1 gcd(nm)=1gcd(nn+1)=1gcd(mm+1)=1
那么 g c d ( n ∗ ( m + 1 ) , m ) = g c d ( n , ( n + 1 ) ∗ m ) = 1 gcd(n * (m + 1) , m ) = gcd (n , (n + 1) * m ) = 1 gcd(n(m+1),m)=gcd(n,(n+1)m)=1
推到这里,我们得到启发,我们可以逆推了,假如当前我们在(x,y),表示成 ( n ∗ ( m + 1 ) ∗ k , m ∗ k ) (n * (m + 1) * k , m * k) (n(m+1)k,mk)或者 ( n ∗ k , ( n + 1 ) ∗ m ∗ k ) (n * k , (n + 1) * m * k) (nk,(n+1)mk),我们很容易通过x和y的大小关系,判断他是 ( n ∗ ( m + 1 ) ∗ k , m ∗ k ) (n * (m + 1) * k , m * k) (n(m+1)k,mk)还是 ( n ∗ k , ( n + 1 ) ∗ m ∗ k ) (n * k , (n + 1) * m * k) (nk,(n+1)mk)。而且我们发现青蛙运动的过程中,x,y坐标的gcd是不变的。
那么我们可以开始逆推,我们假设 x > y x > y x>y,那么就是 ( n ∗ ( m + 1 ) ∗ k , m ∗ k ) (n * (m + 1) * k , m * k) (n(m+1)k,mk),可以走到他的点只有 ( n ∗ k , m ∗ k ) (n * k, m * k) (nk,mk)
因为过程中,x,y坐标的gcd是不变的,所以我们一开始的就把他除掉,这样我们只需要关心当前 x % (y + 1) ==0,判断这个点是否还有点可以走到他。处理完,这条路径上有点的数量加上原始点本身就是答案。

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int t; cin >> t;
    for(int ca = 1; ca <= t; ca++) {
        LL x, y; 
        cin >> x >> y;
        if(x < y) swap(x, y);
        LL g = __gcd(x, y);
        x /= g; y /= g;
        LL ans = 1;
        while(x % (y + 1) ==0) {
            ans++;
            x = x / (y + 1);
            if(x < y) swap(x, y);
        }
        cout << "Case #" << ca << ": ";
        cout << ans << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值