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 ,也就是说 g c d ( 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
x y ) n k m k ) (x,y)可以表示为(n * k ,m * k) ,他可以去 ( n ( m + 1 ) k , m k ) (n * (m + 1) * k , m * k) 或者 ( n k , ( n + 1 ) m k ) (n * k , (n + 1) * m * k)
我们发现 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
因为 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
那么 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
推到这里,我们得到启发,我们可以逆推了,假如当前我们在(x,y),表示成 ( n ( m + 1 ) k , m k ) (n * (m + 1) * k , m * k) 或者 ( n k , ( n + 1 ) m k ) (n * k , (n + 1) * m * k) ,我们很容易通过x和y的大小关系,判断他是 ( n ( m + 1 ) k , m k ) (n * (m + 1) * k , m * k) 还是 ( n k , ( n + 1 ) m k ) (n * k , (n + 1) * m * k) 。而且我们发现青蛙运动的过程中,x,y坐标的gcd是不变的。
那么我们可以开始逆推,我们假设 x > y x > y ,那么就是 ( n ( m + 1 ) k , m k ) (n * (m + 1) * k , m * k) ,可以走到他的点只有 ( n k , m k ) (n * k, m * k)
因为过程中,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;
}

猜你喜欢

转载自blog.csdn.net/dawuga/article/details/83242587