您的位置:首页 > 其它

poj2429 GCD & LCM Inverse 因数分解pollard_rho算法

2016-03-04 09:14 435 查看
题意:已知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
,a
,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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: