题目:
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 17978 | Accepted: 3331 |
Description
Input
Output
Sample Input
3 60
Sample Output
12 15
题意:输入两个数的最大公约数和最小公倍数,求这两个数。如果有多组,输出和最小的一对。
思路:
设这两个数分别为:x , y。
那么 必然有 gcd(x,y)*k1 = x ; gcd(x,y)*k2 = y。
由 :x*y / gcd(x,y)= lcm(x,y) 变形得=>> x*y = lcm*gcd;
则:(gcd*k1) * (gcd*k2) = lcm*gcd.
化简得:k1*k2 = lcm/gcd
若我们找到一组k1,k2,满足:k1*k2 = lcm/gcd 的关系,那么k1*gcd就是可能的x,k2*gcd就是可能的y。
我们还应该注意到由于 k1 = x/gcd , k2 = y/gcd 。那么一定有gcd(k1,k2)=1 。
所以我们可以将lcm/gcd进行质因数分解,之后将质因数分别再凑为两堆,一堆相乘结果就是x ,令一堆就是y。特别要注意的是,由于gcd(k1,k2)=1 ,那么为了保证这个性质,分解出的质因数若存在多个,要再乘回去,否则gcd(k1,k2)就会等于那个质因数了。
题设还有最后一个条件:输出和最小的一对。由于x*y =gcd*lcm , 那么求和最小的一对也就是求差最小的一对解。而要使,差最小,无非就是使分解出的两个数都接近sqrt(lcm/gcd),所以我们将所有质因数的组合进行dfs,找到最优解即可。
代码:
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<set>typedef long long ll;using namespace std;const int INF = 0x3f3f3f3f;
const int N = 5500;
const int Times = 10; ll ct,cnt;
ll fac[N];
ll f[N];
ll ans;ll gcd(ll a , ll b){return b==0? a:gcd(b,a%b);
}ll multi(ll a , ll b , ll m){ll ans = 0;a %= m;while(b){if(b&1){ans = (ans+a)%m;b--;}b >>= 1;a = (a+a)%m;}return ans;
}ll quick_mod(ll a , ll b , ll m){ll ans = 1;a %= m;while(b){if(b&1){ans = multi(ans , a , m);b--;}b>>=1;a = multi(a,a,m);}return ans;
}bool Miller_Rabin(ll n){if(n==2) return true;if(n<2 || !(n&1)) return false;ll m = n-1;int k = 0;while((m&1)==0){k++;m>>=1;}for(int i = 0 ; i<Times ; i++){ll a = rand()%(n-1)+1;ll x = quick_mod(a,m,n);ll y = 0;for(int j = 0 ; j<k ; j++){y = multi(x,x,n);if(y==1 && x!=1 && x!=n-1) return false;x = y;}if(y!=1) return false;}return true;
}ll pollard_rho(ll n , ll c){ll i = 1 , k=2;ll x = rand()%(n-1)+1;ll y = x;while(true){i++;x = (multi(x,x,n)+c)%n;ll d = gcd((y-x+n)%n , n);if(1<d && d<n) return d;if(y == x) return n;if(i == k){y = x;k <<= 1;}}
}void find(ll n , int c){if(n == 1) return;if(Miller_Rabin(n)){fac[ct++] = n;return;}ll p = n;ll k = c;while(p >= n) p = pollard_rho(p , c--);find(p , k);find(n/p , k);
}void findx(ll i , ll x , ll q){if(i==cnt) return;if(x>ans && x<=q) ans = x;findx(i+1 , x , q);x *= f[i];if(x>ans && x<=q) ans = x;findx(i+1 , x , q);
}int main(){ll a,b;while(scanf("%lld %lld",&a,&b)!=EOF){if(a == b){printf("%lld %lld\n",a,b);continue;}ct = 0;ll n = b/a;find(n,120);sort(fac,fac+ct);f[0] = fac[0]; cnt = 0;for(int i = 1 ; i<ct ; i++){if(fac[i] == fac[i-1]){f[cnt] = f[cnt] * fac[i];}else{cnt++;f[cnt] = fac[i];}}cnt++;ll goal = (ll)sqrt(n*1.0);ans = 1;findx(0,1,goal);printf("%lld %lld\n" , ans*a , n/ans*a);}return 0;
}