GCD & LCM Inverse
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 20548 Accepted: 3774
Description
Given two positive integers a and b, we can easily calculate the greatest common divisor (GCD) and the least common multiple (LCM) of a and b. But what about the inverse? That is: given GCD and LCM, finding a and b.
Input
The input contains multiple test cases, each of which contains two positive integers, the GCD and the LCM. You can assume that these two numbers are both less than 2^63.
Output
For each test case, output a and b in ascending order. If there are multiple solutions, output the pair with smallest a + b.
Sample Input
3 60
Sample Output
12 15
题目大概意思:
给出两个正整数 ,其中 能够被 整除,求两个正整数 ,使得 , .若存在多组 ,则输出 最小的一组。
分析:
意味着 ,即 与 互质,因此
不妨设 ,则求满足 的和最小的 这一问题可以转化为求满足 的和最小的 .
为使 , 和 不能有相同的质因子;为了使 ,一定有 .
因此,如果把 进行质因子分解,则 可以被表示成若干质数的乘积的形式:
则解一定可以被表示成这样的形式:
由于 ,而前 个质数的乘积已经大于 ,因此最多有不超过 个不同的质因子,即上式中 ,可以通过枚举所有可能的组合在 的时间复杂度内来找到和最小的 .
因此,如果我们可以对 也就是 进行质因子分解,那么就可以得到最终答案。
朴素的方法是通过对不超过 的所有质数进行试除来分解质因子,可这里的可能 高达 ,朴素的算法无法在时间和内存限制内得到答案。
因此需要采用时间和空间上都更为优秀的 算法 来对 进行质因子分解, 算法的期望时间复杂度为 ,因此算法的总复杂度为 .
下面贴代码:
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <climits>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;
const int MAX_N = 1000;
const int S = 20;
ull factor[MAX_N];
int fcnt;
ull gcd(ull a, ull b); // 计算 gcd(a, b)
ull mult_mod(ull a, ull b, ull m); // 计算 a*b % m
ull pow_mod(ull x, ull p, ull m); // 计算 x^p % m
bool check(ull a, ull n, ull x, ull t); // 进行一轮检测, 确定是合数返回 true, 否则返回 false
bool Miller_Rabin(ull n); // 是素数返回 true, 否则返回 false
ull Pollard_rho(ull x, ull c);
void find_factor(ull x); // 对 x 进行素数分解, 调用前应将 fcnt 初始化为0
ull fp[MAX_N];
int main()
{
ull a, b;
srand(time(0));
while (~scanf("%llu%llu", &a, &b))
{
if (a == b)
{
printf("%llu %llu\n", a, b);
continue;
}
b /= a;
fcnt = 0;
find_factor(b);
sort(factor, factor + fcnt);
fcnt = unique(factor, factor + fcnt) - factor;
for (int i = 0; i < fcnt; ++i)
{
ull& cur = fp[i];
cur = factor[i];
while (!(b % cur))
{
cur *= factor[i];
}
cur /= factor[i];
}
ull x, y, mt = ULLONG_MAX;
for (int i = (1 << fcnt) - 1; i >= 0; --i)
{
ull tx = 1, ty = 1;
for (int j = 0; j < fcnt; ++j)
{
if (i >> j & 1)
{
tx *= fp[j];
}
else
{
ty *= fp[j];
}
}
if (tx + ty < mt)
{
mt = tx + ty;
x = min(tx, ty);
y = max(tx, ty);
}
}
printf("%llu %llu\n", x * a, y * a);
}
return 0;
}
ull gcd(ull a, ull b)
{
if (a == 0)return 1;
while (b)
{
ull t = a % b;
a = b;
b = t;
}
return a;
}
ull mult_mod(ull a, ull b, ull m)
{
a %= m;
b %= m;
ull res = 0;
while (b)
{
if (b & 1)
{
res = (res + a) % m;
}
a <<= 1;
if (a >= m) a -= m;
b >>= 1;
}
return res;
}
ull pow_mod(ull x, ull p, ull m)
{
ull res = 1;
x %= m;
while (p)
{
if (p & 1)
{
res = mult_mod(res, x, m);
}
x = mult_mod(x, x, m);
p >>= 1;
}
return res;
}
bool check(ull a, ull n, ull x, ull t)
{
ull res = pow_mod(a, x, n);
ull last = res;
for (int i = 1; i <= t; i++)
{
res = mult_mod(res, res, n);
if (res == 1 && last != 1 && last != n - 1) return true;
last = res;
}
if (res != 1) return true;
return false;
}
bool Miller_Rabin(ull n)
{
if (n < 2) return false;
if (n == 2) return true;
if (!(n & 1)) return false;
ull x = n - 1;
ull t = 0;
while (!(x & 1))
{
x >>= 1;
++t;
}
for (int i = 0; i < S; i++)
{
ull a = rand() % (n - 1) + 1;
if (check(a, n, x, t))
return false;
}
return true;
}
ull Pollard_rho(ull x, ull c)
{
ull i = 1, k = 2;
ull x0 = rand() % x;
ull y = x0;
while (1)
{
i++;
x0 = (mult_mod(x0, x0, x) + c) % x;
ull d = gcd(y > x0 ? y - x0 : x0 - y, x);
if (d != 1 && d != x) return d;
if (y == x0) return x;
if (i == k)
{
y = x0;
k += k;
}
}
}
void find_factor(ull x)
{
if (Miller_Rabin(x))
{
factor[fcnt++] = x;
return;
}
ull p = x;
while (p >= x)p = Pollard_rho(p, rand() % (x - 1) + 1);
find_factor(p);
find_factor(x / p);
}