1.题目链接。题目大意:给出两个数的gcd和lcm,求这两个数和最小是多少?
2.分析:。那么我们可以简单的推导一下:
这里n是一个整数,并且:
说明n一定是由两个互质的数乘起来的。那么我们枚举n的因子,然后找一下最小的即可。但是这里似乎有问题,因为n可以到1e18.对于一个数的分解,我们可以做到sqrt(n)。显然不行。从另外一个角度考虑,因子是用这个数进行素因子分解之后产生的,两个互质就是说二者拥有不同的素因子。如果我们能够找到这个数所有的素因子,然后二进制枚举一下,因为longlong范围内,一个数的素因子的种类不会超过20种。但是对于一个大整数进行素因子分解也是np困难的。不过有随机分解算法,这样就可以在期望复杂度不高的情况下解决这个问题。
#include <iostream>
#include <string.h>
#include <string>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <map>
using namespace std;
typedef long long LL;
const int times = 20;//随机算法判定次数
map <LL, int>mp;//质因子的数目
LL Multi(LL a, LL b, LL MOD) {
LL ans = 0;
while (b) {
if (b & 1) ans = (ans + a) % MOD;
b >>= 1;
a = (a + a) % MOD;
}
return ans;
}
LL Pow(LL a, LL b, LL MOD) {
a = a % MOD;
LL ans = 1;
while (b) {
if (b & 1) ans = Multi(ans, a, MOD);
b >>= 1;
a = Multi(a, a, MOD);
}
return ans;
}
bool test(LL a, LL n, LL x, LL t)//miLLer_rabin算法的核心
{
LL res = Pow(a, x, n);//a^x mod n
LL last = res;
for (int i = 1; i <= t; i++) {
res = Multi(res, res, n);//res=res*res mod n
if (res == 1 && last != 1 && last != n - 1) return true;
last = res;
}
if (res != 1) return true;
return false;
}
bool miLLer_rabin(LL n) {
if (n < 2) return false;
if (n == 2) return true;
if ((n & 1) == 0) return false; //偶数
LL x = n - 1, t = 0;
while ((x & 1) == 0)//n-1=(2^t)*x;
{
x >>= 1;
t++;
}
for (int i = 0; i < times; i++)//进行随机判定
{
LL a = rand() % (n - 1) + 1;//随机找0~n-1的整数
if (test(a, n, x, t)) return false;
}
return true;
}
LL factor[100];//保存质因数分解结果
int tot;//记录质因数个数,下标从0开始
LL GCD(LL a, LL b) {
if (a < 0) return GCD(-a, b);
if (b == 0) return a;
return GCD(b, a%b);
}
LL pollard_rho(LL x, LL c) {
LL i = 1, k = 2;
LL x0 = rand() % x;
LL y = x0;
while (1) {
i++;
x0 = (Multi(x0, x0, x) + c) % x;
LL d = GCD(y - x0, x);
if (d != 1 && d != x) return d;
if (y == x0) return x;
if (i == k) {
y = x0;
k += k;
}
}
}
//对n进行素因子分解
void find_factor(LL n) {
if (miLLer_rabin(n))//若为素数
{
factor[tot++] = n;
mp[n]++;
return;
}
LL p = n;
while (p >= n) p = pollard_rho(p, rand() % (n - 1) + 1);
find_factor(p);
find_factor(n / p);
}
LL pw(LL a, LL b) {
LL ans = 1;
while (b) {
if (b & 1) ans = ans * a;
b >>= 1;
a *= a;
}
return ans;
}
int main() {
LL a, b;
while (cin >> a >> b) {
if (a == b) { printf("%lld %lld\n", a, b); continue; }
tot = 0;
mp.clear();
LL n = b / a;
find_factor(n);
sort(factor, factor + tot);
tot = unique(factor, factor + tot) - factor;
LL ans = b, aa, bb;
int all = (1 << tot);
for (int i = 0; i < all; i++) {
LL tp1 = 1, tp2 = 1;
for (int j = 0; j < tot; j++) {
if (i&(1 << j)) {
LL tmp = pw(factor[j], mp[factor[j]]);
tp1 *= tmp;
}
}
tp2 = n / tp1;
if (ans > tp1*a + tp2 * a)
{
ans = tp1 * a + tp2 * a;
aa = min(tp1, tp2);
bb = max(tp1, tp2);
}
}
printf("%lld %lld\n", aa*a, bb*a);
}
return 0;
}