【poj2429】GCD & LCM Inverse 因数分解pollard_pho算法

       题意:已知gcd(a,b)和lcm(a,b),求a,b使得a+b最小。

       令p=lca(a,b)/gcd(a,b),那么显然a=pu,b=pv且gcd(u,v)=1。那么只需要将p分解质因数,然后把相同的质因数并起来,一遍dfs即可。

       质因数分解的pollard_pho启发式算法,可以在期望n^(1/4)的时间内找到n的一个因数,然后递归分解即可。显然分解的次数不会太多,因此时间上可以接受。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cstdlib>
#include<algorithm>
#define ll long long
#define N 205
using namespace std;

ll n,m,c[N],a[N],ansx,ansy; int cnt;
ll ksc(ll x,ll y,ll p){
	ll t=0; for (; y; y>>=1,x=(x<<1)%p) if (y&1) t=(t+x)%p;
	return t;
}
ll ksm(ll x,ll y,ll p){
	ll t=1; for (; y; y>>=1,x=ksc(x,x,p)) if (y&1) t=ksc(t,x,p);
	return t;
}
bool isprm(ll x){
	if (x==2) return 1; if (x==1 || !(x&1)) return 0;
	ll t=x-1; int len=0,i,j;
	for (; !(t&1); t>>=1) len++;
	for (i=1; i<=10; i++){
		ll k=ksm(rand()%(x-1)+1,t,x);
		for (j=1; j<=len; j++,k=ksc(k,k,x))
			if (j<len-1 && ksc(k,k,x)==1 && k!=1 && k!=x-1) return 0;
		if (k!=1) return 0;
	}
	return 1;
}
ll gcd(ll x,ll y){ return (y)?gcd(y,x%y):x; }
ll pho(ll x){
	ll u=rand()%(x-1)+1,v=u,w,t=1; int i=2,k=2;
	while (!w || w==2) w=rand()%(x-1)+1;
	for (; t==1; i++){
		if (i==k){ v=u; k<<=1; }
		u=(ksc(u,u,x)+x-w)%x;
		t=gcd(v-u+x,x);
	}
	return t;
}
void divide(ll x){
	if (x==1) return; else if (isprm(x)) c[++c[0]]=x; else
	if (!(x&1)){ c[++c[0]]=2; divide(x/2); } else{
		ll t=pho(x); divide(t); divide(x/t);
	}	
}
void dfs(int k,ll x,ll y){
	if (x+y>=ansx+ansy) return;
	if (k>cnt){
		ansx=x; ansy=y; return;
	}
	dfs(k+1,x*a[k],y); dfs(k+1,x,y*a[k]);
}
int main(){
	srand(20160304);
	while (~scanf("%lld%lld",&m,&n)){
		c[0]=0; divide(n/m);
		sort(c+1,c+c[0]+1); int i; cnt=0;
		for (i=1; i<=c[0]; i++)
			if (i==1 || c[i]!=c[i-1]) a[++cnt]=c[i];
			else a[cnt]*=c[i];
		ansx=1; ansy=n/m; dfs(1,1,1);
		if (ansx>ansy) swap(ansx,ansy);
		printf("%lld %lld\n",ansx*m,ansy*m);
	}
	return 0;
}


by lych

2016.3.4

你可能感兴趣的:(数学,DFS,质因数分解,pollard_pho)