LCM Walk
题意:一只青蛙在无穷大的棋盘上跳跃,规则如下:青蛙当前位置是(x, y);那么下一步,青蛙只能跳到(x+lcm(x, y), y)或(x, y+lcm(x, y));题目给出一个终点(ex, ey),问青蛙的起点有几种情况;
思路:
假设青蛙由(x, y)跳到了(x+lcm(x, y) = ex, y = ey);因为lcm(x, y)>=x && lcm>=y; 所以ex>ey; 可知,当前点是(ex, ey)&&ex>ey时,前一个状态一定在(x, ey);现在就可以推公式了;
lcm(x, y)=x*y/gcd(x, y);
令 x=m1*gcd(x, y), y=m2*gcd(x, y); m1, m2互质;
x+lcm(x, y)=m1*gcd(x, y)+m1*gcd(x, y)*m2*gcd(x, y)/gcd(x, y)=m1*gcd(x, y)+m1*m2*gcd(x, y)=m1*(1+m2)*gcd(x, y);
又 m1, m2互质, 所以 m1, (1+m2) 互质, 且m1*(1+m2) 与 m2 互质, 所以m1*(1+m2)*gcd(x, y) 与 m2*gcd(x, y)的gcd=gcd(x, y);
又ey=y=m2*gcd(x, y); 所以gcd(ex, ey)=gcd(x, y);
令 g=gcd(ex, ey);
m2=ey/g;
m1*(1+m2)*g=ex->m1g=ex/(1+m2)=ex/(1+ey/g)->x=ex/(1+ey/g);
所以(ex, ey)可由(ex/(1+ey/gcd(ex, ey)), ey)转移过来;
当然上述部分的前提条件是ex>ey;但是当ex<ey时前一个状态不就是(ex, ey/(1+ex/gcd(ex, ey)))吗?所以当ex<ey时,只需将ex,ey交换,然后继续计算即可;那么找到什么时候状态就停止了呢?因为ex=m1*(m2+1)*g=m1*(m2*g+g)=m1*(ey+g),所以若当前状态不满足ex是ey+g的倍数,就不会有前一个状态了;
#include <bits/stdc++.h>
using namespace std;
int gcd(int a, int b){
return b==0?a:gcd(b, a%b);
}
int main(){
int T, cas=0;
scanf("%d", &T);
while(T--){
int ex, ey;
scanf("%d%d", &ex, &ey);
if(ex<ey) swap(ex, ey);
int ans=1;
int g=gcd(ex, ey);
while(ex%(g+ey)==0){
ans++;
int tx, ty;
ty=ey;
tx=ex/(1+ey/g);//这里如果化简为tx=ex*g/(g+ey)就需要用long long型,因为ex*g超了int范围;
ex=tx, ey=ty;
//printf("x:%d y:%d\n", ex, ey);
if(ex<ey) swap(ex, ey);
}
printf("Case #%d: %d\n", ++cas, ans);
}
return 0;
}