HDU-5584
一般题目中含有lcm的时候尽量往gcd上转。。利用gcd的性质解决问题
题目链接 https://vjudge.net/problem/HDU-5584
题意:从初始位置(x,y)开始每次可以走lcm(x,y)步到(x+lcm,y)或(x,y+lcm) (这里的x y为当前的x和y) 给你最终的x和y问有多少种可能的起始点。
思路:我们先从起点正着推:假设起点为(x,y),并且假设第一步变为(x,y+lcm(x,y) )
我们对前后两点分析:
设gcd(x,y)=k 那么 x 和 y 可以表示成 mk nk,且m n互质。 lcm(x,y)=lcm(mk,nk)=mnk
那么后点可以表示为:(mk , nk(m+1) )
由于m和n互质 1和m+1互质 那么gcd(mk,nk(m+1)) = k 也就是说前后点的gcd不变
结论就出来了:在坐标变化过程中,每个点的gcd不变恒为k
又由于lcm(x,y)>=max(x,y) 我们已知终点,前一次加上lcm的点一定是两点中较大的那一个。
知道这两条性质,每次只有一种可能的结果,每次至少缩小一半的数据规模,就可以倒推了,每倒推多一步就多一个可能的起始点。(终点本身也可以是起始点)
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <map>
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);++(i))
#define ll long long
#define ld long double
int
gcd(int x, int y)
{
return (y==0)?x:gcd(y, x%y);
}
using namespace std;
int
main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T; cin>>T;
int x, y;
for(int kase=1; kase<=T; kase++)
{
int c=1;
cin>>x>>y;
cout<<"Case #"<<kase<<": ";
int k=gcd(x, y);
if(x>y) { swap(x, y); }
while(y%(x+k)==0)
{
c++;
y=y/(x/k+1);
if(x>y)
{
swap(x, y);
}
k=gcd(x, y);
}
cout<<c<<endl;
}
return 0;
}
2016icpc大连区域赛 D a simple math problem
https://vjudge.net/problem/HDU-5974
题目大意: x+y = a lcm(x,y)=b x<y 求解x和y 若无解输出 no solution
分析: 跟上题同样的设法: 设 gcd(x,y)=k, x=mk y=nk 且m n互质 lcm(x,y)=mnk
那么 gcd(a,b) = gcd( (m+n)k , mnk ) 由于m n互质,那么m+n和mn也互质 所以gcd(a,b)=k
得到结论:gcd(x,y)=gcd(a,b)
那么条件就变为: (m+n) = a/k
mn = b/k
gcd(x,y)=gcd(a,b)=k
a/k和b/k均已知设为c和d 题目就变为解一个关于m和n的二元一次方程。又由于m和n是轮换式,解出来的两组解一定是两组意义上相同的解。
当m和n为正整数解的时候输出,非正整数或delta<0输出 no solution