您的位置:首页 > 其它

POJ2429 GCD&LCM Inverse(整数分解,由GCD+LCM求a,b)

2013-08-14 21:20 543 查看


POJ2429 GCD&LCM Inverse(整数分解,由GCD+LCM求a,b)

分类: 数论2013-02-12
22:00 180人阅读 评论(1) 收藏 举报

题目:GCD & LCM Inverse

题意:给你两个数G和L分别是a,b的最大公约数和最小公倍数,求a,b。(有多组a,b的情况下取a+b最小的)

分析:由于 G和L分别是a,b的最大公约数和最小公倍数,那么G一定整除L,否则就没有解了。

进一步可以知道L/G的素因子分解式中,同一项不会同时出现在a,b中,因为相同的在G中已经除掉了.

那么有:

,所以我们现在只需要枚举L/G的约数,枚举的一个x在a中,那么另一个(L/G)/x就是在b中,但是我们知道




,

,所以思路就是对L/G先分解,因为这个数很大,所以就用Pollard-rho分解法吧,分解之后,利用


dfs找因子,然后每找到一个就判断一次来记录a+b最小的,然后就分析完毕。

[cpp] view
plaincopy

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <algorithm>

#include <iostream>

using namespace std;

#define LL unsigned long long

const int Times=10;

const LL INF=(LL)1<<61;

const int N=550;

LL n,m,ct,cnt,mini,mina,minb,ans;

LL fac
,num
;

LL gcd(LL a,LL b)

{

return b? gcd(b,a%b):a;

}

LL multi(LL a,LL b,LL m)

{

LL ans=0;

while(b)

{

if(b&1)

{

ans=(ans+a)%m;

b--;

}

b>>=1;

a=(a+a)%m;

}

return ans;

}

LL quick_mod(LL a,LL b,LL m)

{

LL ans=1;

a%=m;

while(b)

{

if(b&1)

{

ans=multi(ans,a,m);

b--;

}

b>>=1;

a=multi(a,a,m);

}

return ans;

}

bool Miller_Rabin(LL n)

{

if(n==2) return true;

if(n<2||!(n&1)) return false;

LL a,m=n-1,x,y;

int k=0;

while((m&1)==0)

{

k++;

m>>=1;

}

for(int i=0;i<Times;i++)

{

a=rand()%(n-1)+1;

x=quick_mod(a,m,n);

for(int j=0;j<k;j++)

{

y=multi(x,x,n);

if(y==1&&x!=1&&x!=n-1) return false;

x=y;

}

if(y!=1) return false;

}

return true;

}

LL Pollard_rho(LL n,LL c)

{

LL x,y,d,i=1,k=2;

y=x=rand()%(n-1)+1;

while(true)

{

i++;

x=(multi(x,x,n)+c)%n;

d=gcd((y-x+n)%n,n);

if(1<d&&d<n) return d;

if(y==x) return n;

if(i==k)

{

y=x;

k<<=1;

}

}

}

void find(LL n,int c)

{

if(n==1) return;

if(Miller_Rabin(n))

{

fac[ct++]=n;

return ;

}

LL p=n;

LL k=c;

while(p>=n) p=Pollard_rho(p,c--);

find(p,k);

find(n/p,k);

}

void dfs(LL c,LL value)

{

LL s=1,a,b;

if(c==cnt)

{

a=value;

b=ans/a;

if(gcd(a,b)==1)

{

a*=n;

b*=n;

if(a+b<mini)

{

mini=a+b;

mina=a;

minb=b;

}

}

return ;

}

for(LL i=0;i<=num[c];i++)

{

if(s*value>mini) return;

dfs(c+1,s*value);

s*=fac[c];

}

}

int main()

{

while(~scanf("%llu%llu",&n,&m))

{

if(n==m)

{

printf("%llu %llu\n",n,m);

continue;

}

mini=INF;

ct=cnt=0;

ans=m/n;

find(ans,120);

sort(fac,fac+ct);

num[0]=1;

int k=1;

for(LL i=1;i<ct;i++)

{

if(fac[i]==fac[i-1])

++num[k-1];

else

{

num[k]=1;

fac[k++]=fac[i];

}

}

cnt=k;

dfs(0,1);

if(mina>minb) swap(mina,minb);

printf("%llu %llu\n",mina,minb);

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: