POJ2429 GCD & LCM Inverse pollard_rho大整数分解-好题

版权声明:希望大家读懂代码,而不是复制粘贴提交 https://blog.csdn.net/pythonbanana/article/details/82909143

题意:
给出两个数的最大公约数和最小公倍数,找出这两个数,并使它们的和最小。
思路:
设gcd = a1a2an,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;
}

猜你喜欢

转载自blog.csdn.net/pythonbanana/article/details/82909143