hdu 5584 最小公倍数
2015年ACM区域赛(上海)的现场赛题。
难度等级:简单题,数学。
FB(First Blood)时间:18分钟。
铜牌队伍在98分钟左右AC。
排行榜的L题: https://luoyongjun999.github.io/rank.html
能力考核:最小公倍数和最大公约数问题、逻辑推理。
题意:
一只青蛙坐在一个网格图上,行和列都是无限的。行的计数从底部开始1, 2, ⋯,列也是这样。青蛙最初的位置是坐标(sx, sy),旅程开始了。
它使用了一种特别的跳跃方法。如果它在坐标(x, y),寻找一个可以被x和y都整除的最小的z,然后向上或向右跳z步,下一步坐标可能是(x+z, y)或(x, y+z)。
经过有限跳跃后(可能是0步),它停在(ex, ey)。然而,它太累了,忘记了它的起始位置。
如果一个个去检查网格的所有坐标,那太笨了!请告诉青蛙一个聪明的办法,到达(ex, ey)的可能的起始位置有多少个?
思路
起点是(x, y),终点是(ex, ey),已知终点,反推起点。
z是x, y的LCM,设x = pt,y = qt,z = pqt。p和q互质。
起点(x, y),下一步可以走到2个位置(x, y + z)或(x + z, y) 。
(1)终点(ex, ey) = (x, y + z)
= (pt, qt + pqt) = (pt, q(1+p)t)
由于p和q(1+p)互质,所以t是最大公约数,可得:t = GCD(ex, ey)。推导起点:
x = pt = ex
y = qt = ey*t/(ex+t)
把起点当成新的终点,继续这个过程。
(2)终点(ex, ey) = (x + z, y)
注意到(1)中y + z > x,即ex < ey,(2)中ex > ey。
只需要先按大小交换ex, ey的顺序,就可以合并成一种情况处理了。
#include <bits/stdc++.h>
#define inf 1000000009
#define db printf("where!\n");
#define pb push_back
using namespace std;
#define ll long long
#define MP std::make_pair
ll gcd(ll x,ll y){return y ? gcd(y,x%y) : x;}
template<class T>inline void read(T &res){
char c;T flag=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
int main()
{
int tt;read(tt);
int cnt=0;
while(tt--){
cout<<"Case #"<< ++cnt <<": ";
int x,y;read(x),read(y);
int ans=1;
if(x>y) swap(x,y);//将小的放前面
while(1){
int t=__gcd(x,y);
int p=x/t;
if(y%(p+1)!=0) break;
int xx=x;
x=y/(p+1),y=xx;
if(__gcd(x,y)!=t) break;
if(x>y) swap(x,y);
ans++;
}
cout<<ans<<endl;
}
return 0;
}