题意:有一只青蛙,它从起点(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;
}