题意:
给gcd(a,b)和lcm(a,b),求a+b最小的a和b。
分析:
miller_rabin素数判定要用费马小定理和二次探测定理。pollard_rho因数分解算法导论上讲的又全又好,网上的资料大多讲不清楚。
代码:
//poj 2429
//sep9
#include <iostream>
#include <map>
#include <vector>
#define gcc 10007
#define max_prime 200000
using namespace std;
typedef long long ll;
vector<int> primes;
vector<bool> is_prime;
ll gcd(ll a,ll b)
{ll m=1;if(!b) return a;while(m){m=a%b;a=b;b=m;}return a;
}ll multi_mod(ll a,ll b,ll mod)
{ll sum=0;while(b){if(b&1) sum=(sum+a)%mod;a=(a+a)%mod;b>>=1;} return sum;
}ll pow_mod(ll a,ll b,ll mod)
{ll sum=1;while(b){if(b&1) sum=multi_mod(sum,a,mod);a=multi_mod(a,a,mod);b>>=1;} return sum;
} bool miller_rabin(ll n,int times)
{if(n<2) return false;if(n==2) return true;if(!(n&1)) return false;ll q=n-1;int k=0;while(!(q&1)){++k;q>>=1;}for(int i=0;i<times;++i){ll a=rand()%(n-1)+1;ll x=pow_mod(a,q,n);if(x==1) continue;for(int j=0;j<k;++j){ll buf=multi_mod(x,x,n);if(buf==1&&x!=1&&x!=n-1)return false;x=buf;}if(x!=1)return false;} return true;
}ll pollard_rho(ll n)
{ll d,i,k,x,y;x=rand()%(n-1)+1;y=x;i=1;k=2;do{++i;d=gcd(n+y-x,n);if(d>1&&d<n)return d;if(i==k)y=x,k*=2;x=((multi_mod(x,x,n)-gcc)%n+n)%n;}while(y!=x);return n;
}bool isPrime(ll n)
{if(n<=max_prime) return is_prime[n];return miller_rabin(n,20);
}void factorize(ll n,map<ll,int>& factors)
{if(isPrime(n))++factors[n];else{for(int i=0;i<primes.size();++i){int p=primes[i];while(n%p==0){++factors[p];n/=p; } }if(n!=1){if(isPrime(n))++factors[n];else{ll d=pollard_rho(n);factorize(d,factors);factorize(n/d,factors);}}}
}pair<ll,ll> solve(ll a,ll b)
{ll c=b/a;map<ll,int> factor; factorize(c,factor);vector<ll> mul_factors;for(map<ll,int>::iterator it=factor.begin();it!=factor.end();++it){ll mul=1;while(it->second){mul*=it->first;it->second--;}mul_factors.push_back(mul);}ll best_sum=1e18,best_x=1,best_y=c;for(int mask=0;mask<(1<<mul_factors.size());++mask){ll x=1;for(int i=0;i<mul_factors.size();++i)if((mask>>i)&1) x*=mul_factors[i];ll y=c/x;if(x<y&&x+y<best_sum){best_sum=x+y;best_x=x;best_y=y;}}return make_pair(best_x*a,best_y*a);
}void ini_primes()
{is_prime=vector<bool>(max_prime+1,true);is_prime[0]=is_prime[1]=false;for(int i=2;i<=max_prime;++i){if(is_prime[i]){primes.push_back(i);for(int j=i*2;j<=max_prime;j+=i)is_prime[j]=false;}}
}int main()
{ll a,b;ini_primes();while(scanf("%I64d%I64d",&a,&b)==2){pair<ll,ll> ans=solve(a,b);printf("%I64d %I64d\n",ans.first,ans.second); }return 0;
}