http://poj.org/problem?id=2429
大致题意:给出两个数的最大公约数a和最小公倍数b,求这两个数,并且要这两个数加起来最小。
方法:b/a求得的值是两个互质的数的乘积, 这题的数比较大, 所以用了模板、
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <algorithm>
using namespace std;
#define Time 12 // Miller测试次数
typedef __int64 ll;
const ll INF = (1LL << 62) + ((1LL<<62)-1);
const int maxC = 240;
ll big_mul(ll a, ll b, ll m) {
ll ret = 0;
a %= m;
while(b) {
if(b & 1) {
ret += a;
if(ret >= m) ret -= m;
}
a *= 2;
if(a >= m) a -= m;
b /= 2;
}
return ret;
}
ll pow_mod(ll x, ll n, ll m) {
ll ret = 1;
x %= m;
while(n) {
if(n & 1) ret = big_mul(ret, x, m);
x = big_mul(x, x, m);
n /= 2;
}
return ret;
}
// 以a为基对n进行Miller次测试并进行二次探测,返回true则是合数
bool Wintess(ll a, ll n) {
ll m = n-1;
int top = 0;
// n-1 = m*(2^top)
while(m % 2 == 0) {
m /= 2;
top++;
}
ll x = pow_mod(a, m, n), y;
for(int i = 0;i < top; i++) {
y = big_mul(x, x, n);
if(y == 1 && (x != 1 && x != n-1))
return true;
x = y;
}
if(y > 1) return true;
return false;
}
// 对n进行ts次 Miller素性测试
bool Miller_Rabin(int ts, ll n) {
if(n == 2) return true;
if(n == 1 || n % 2 == 0) return false;
srand(time(NULL));
for(int i = 0;i < ts; i++) {
ll a = rand() % (n-1) + 1;
if(Wintess(a, n)) return false;
}
return true;
}
ll ans;
ll gcd(ll a, ll b) {
return b ? gcd(b, a%b) : a;
}
// 对n进行因式分解,找出n的一个因子,该因子不一定是最小的
ll Pollard(ll n, int c) {
srand(time(NULL));
ll i = 1, k = 2, x = rand()%n, y = x;
while(true) {
i++;
x = (big_mul(x, x, n) + c) % n;
ll d = gcd(y - x, n);
if(d > 1 && d < n) return d;
if(y == x) return n; // 如果该数已经出现过,直接返回
if(i == k) {
y = x; k <<= 1;
}
}
}
// 找出所有素因子
void solve(ll n, int c) {
if(n == 1) return ;
// 判断是否为素数
if(Miller_Rabin(Time, n)) {
if(ans > n) ans = n;
return ;
}
ll m = n;
while(m == n) { // 找出n的一个因子
m = Pollard(n, c--);
}
solve(m, c);
solve(n/m, c);
}
int main() {
ll pp, qq;
ll num[52];
while(scanf("%I64d%I64d" , &pp, &qq) == 2) {
int i, j;
ll tt = qq / pp;
int tot = 0;
for(i = 1; i <= 50; i++)
num[i] = 1;
//Miller_Rabin(Time, tt)这个函数是用来判断tt是否为质数
while(!Miller_Rabin(Time, tt)){
if(tt == 1)
break;
//solve(tt, maxC)这个函数是用来求tt 的最小的质因数,ans就是这个质因数
ans = INF;
solve(tt, maxC);
tot++;
while(tt%ans == 0){
num[tot] *= ans;
tt /= ans;
}
}
if(tt > 1)
num[++tot] = tt;
ll res = INF;
int temp = 1;
for(i = 1; i <= tot; i++)
temp *= 2;
ll p, q;
ll ansp, ansq;
for(i = 0; i < temp; i++){
p = q = 1;
if((i&1))
p *= num[1];
else
q *= num[1];
for(j = 1; j < tot; j++){
if((i>>j)&1){
p *= num[j+1];
// printf("p = %I64d\n", p);
}
else{
q *= num[j+1];
//printf("q = %I64d\n", q);
}
}
if(p+q < res){
ansp = p;
ansq = q;
res = p+q;
}
}
if(ansp > ansq) swap(ansp, ansq);
printf("%I64d %I64d\n",ansp*pp, ansq*pp);
}
return 0;
}