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

来源:互联网 发布:淘宝首页设计教程 编辑:程序博客网 时间:2024/06/03 17:02

题意:有一只青蛙,它从起点(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;}
1 0
原创粉丝点击