版权声明:希望大家读懂代码,而不是复制粘贴提交 https://blog.csdn.net/pythonbanana/article/details/82909143
题意:
给出两个数的最大公约数和最小公倍数,找出这两个数,并使它们的和最小。
思路:
设gcd = a1a2…an,lcm = a1a2*…ank;则lcm/gcd = k;现在题目转化为:求两个互质的数a,b满足a*b =k,且a+b最小。
这里首先想到质因数分解,但是平时的埃式筛选法还有欧拉筛选法都不行,空间太大。
这里要用到一种很巧妙的随机算法-Pollard_rho(大整数质因数分解)还有Miller_rabin随机算法(判断一个大整数是否是质数)。
两者算法的具体解析请看传送门。
大整数质因数分解Pollard_rho算法传送门
大整数素数判定Miller_rabin算法传送门
AC code:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
//#define INF 0x3f3f3f//使用这个INF会WA
using namespace std;
typedef long long LL;
const LL INF=(LL)1<<61;
const int maxn = 2e5;
const int times = 100;
map<LL,int> mp;
int cnt = 0;
LL gc = 0,lc = 0,c = 234237,k = 0;
LL minv = INF;
LL resa = 0,resb = 0;
LL gcd(LL a,LL b){
return b == 0 ? a : gcd(b,a%b);
}
LL q_mul(LL a,LL b,LL mod){
LL res = 0;
while(b > 0){
if(b & 1){
res = (res + a) % mod;
}
a = (a + a) % mod;
b >>= 1;
}
return res;
}
LL q_pow(LL a,LL b,LL mod){
LL res = 1;
while(b > 0){
if(b & 1){
res = q_mul(res,a,mod);
}
a = q_mul(a,a,mod);
b >>= 1;
}
return res;
}
bool witness(LL a,LL n){
LL temp = n - 1;
int j = 0;
while(temp % 2 == 0){
temp /= 2;
j++;
}
LL x = q_pow(a,temp,n);
if(x == n-1 || x == 1){
return true;
}
while(j--){
x = q_mul(x,x,n);
if(x == n-1){
return true;
}
}
return false;
}
bool Miller_rabin(LL n){
if(n == 2){
return true;
}
if(n < 2 || (n % 2 == 0 && n != 2)){
return false;
}
for(int i = 0;i < times;++i){
LL r = rand() % (n - 2) + 1;//n-1和n-2都可以
if(witness(r,n) == false){
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 = (q_mul(x,x,n) + c) % n;
LL d = gcd(y - x,n);
if(1 < d && d < n){
return d;
}
if(y == x){
return n;
}
if(i == k){
y = x;
k <<= 1;
}
}
}
void find(LL n,LL c){
if(n == 1){
return ;
}
if(Miller_rabin(n) == true){
mp[n]++;
return ;
}
LL p = n;
while(p >= n){
p = pollard_rho(p,c--);
}
find(p,c);find(n/p,c);
}
void dfs(int depth,LL a){
if(depth == cnt){
LL b = k / a;
if(gcd(a,b) == 1){
if(a + b < minv){
minv = a + b;
resa = a;resb = b;
}
}
return ;
}
map<LL,int>::iterator it = mp.begin();
for(int i = 0;i < depth;++i){
it++;
}
//cout << "hah " << it->first << " " << it->second << endl;
LL temp = q_pow(it->first,it->second,INF);
//cout << temp << endl;
if(a * temp < minv){
dfs(depth + 1,a * temp);
}
if(a < minv){
dfs(depth + 1,a);
}
}
void solve(LL n,LL c){
find(k,c);
cnt = mp.size();
/*
map<LL,int>::iterator it = mp.begin();
for(it = mp.begin();it != mp.end();it++){
cout << "em " << it->first << " " << it->second << endl;
}
*/
dfs(0,1);
if(resa > resb){
swap(resa,resb);
}
printf("%I64d %I64d\n",resa * gc,resb * gc);
}
int main(){
while(~scanf("%I64d %I64d",&gc,&lc)){
minv = INF;
c = 2137342;
mp.clear();
k = lc / gc;
solve(k,c);
}
return 0;
}