2015-ICPC-ShangHai现场赛-L-数论-gcd

40 篇文章 0 订阅
5 篇文章 0 订阅

题意:有一只青蛙,它从起点(x,y)出发,每次它会走lcm(x,y)步到达点(x+lcm(x,y),y)或点(x,y+lcm(x,y)),最终,它会到达点(ex,ey),现给你终点(ex,ey),要你求出它的起点有多少种可能。

题解:
首先来个公式:lcm(a,b)*gcd(a,b)=a*b
这里我简单证明一下:设a=x^k1*y^k2…,b=x^k3*y^k4…,gcd(a,b)=x^(min(k1,k3))*y^(min(k2,k4)),而lcm(a,b)=x^(max(k1,k3))*y^(max(k2,k4)),说到这里应该就清楚了吧。

我们设青蛙从(a,b)跳到(x,y)(x<y),那么我们怎么从(x,y)倒推回去呢?
(这里有一点要注意,那就是x肯定是a或者b,而y是a或b加上lcm(a,b)而来,即大的是上一点中某个数+lcm(上一点)而来,小的是上一点某个数)

我们设a=k1*q,b=k2*q,(k1与k2互质)(这里假设y=b+lcm(a,b)),那么gcd(a,b)=q,lcm(a,b)=k1*k2*q。所以y=(1+k1)*k2*q,我们想从y倒推到b时,b=y/(1+k1)=y/(1+x/gcd(x,y))。(因为k1与k2互质,k1与k1+1互质,所以gcd(a,b)=gcd(x,y)=q)

就这样一直倒推上去即可。

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

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

int main()
{
    int t,a,b,x,ans;
    scanf("%d",&t);
    for(int ca=1;ca<=t;ca++)
    {
        scanf("%d%d",&a,&b);
        if(a>b) swap(a,b);
        ans=1;  //跳跃次数为0,终点即起点
        x = gcd(a,b);
        while(b%(x+a)==0) //满足该条件说明有上个点,我公式都给了,自己想一想
        {
            ans++;
            b = b/(a/x+1);
            if(a>b) swap(a,b);
            x = gcd(a,b);
        }
        printf("Case #%d: %d\n",ca,ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值