您的位置:首页 > 其它

2429 GCD & LCM Inverse 大整数分解质因数

2010-08-22 22:19 295 查看
GCD & LCM Inverse

Time Limit: 2000MSMemory Limit: 65536K
Total Submissions: 3966Accepted: 680
Description
Given two positive integers a and b, we can easily calculate the greatest common divisor (GCD) and the least common multiple (LCM) of a and b. But what about the inverse? That is: given GCD and LCM, finding a and b.
Input
The input contains multiple test cases, each of which contains two positive integers, the GCD and the LCM. You can assume that these two numbers are both less than 2^63.
Output
For each test case, output a and b in ascending order. If there are multiple solutions, output the pair with smallest a + b.
Sample Input
3 60

Sample Output
12 15

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<algorithm>
//看情况选择下列两个
//#define bignum unsigned long long
#define bignum unsigned __int64
using namespace std;
//求a,b的最大公约数
bignum gcd(bignum a,bignum b)
{
return b==0?a:gcd(b,a%b);
}
//求a*b%c,因为a,b很大,所以要先将b写成二进制数,再加:例如3*7=3*(1+2+4);
bignum mulmod(bignum a,bignum b,bignum c)
{
bignum cnt=0,temp=a;
while(b)
{
if(b&1) cnt=(cnt+temp)%c;
temp=(temp+temp)%c;
b>>=1;
}
return cnt;
}
//求a^b%c,再次将b写成二进制形式,例如:3^7=3^1*3^2*3^4;
bignum powmod(bignum a,bignum b,bignum c)
{
bignum cnt=1,temp=a;
while(b)
{
if(b&1) cnt=mulmod(cnt,temp,c);//cnt=(cnt*temp)%c;
temp=mulmod(temp,temp,c);//temp=(temp*temp)%c;
b>>=1;
}
return cnt;
}
//Miller-Rabin测试n是否为素数,1表示为素数,0表示非素数
int pri[10]={2,3,5,7,11,13,17,19,23,29};
bool Miller_Rabin(bignum n)
{
if(n<2) return 0;
if(n==2) return 1;
if(!(n&1)) return 0;
bignum k=0,m;
m=n-1;
while(m%2==0) m>>=1,k++;//n-1=m*2^k
for(int i=0;i<10;i++)
{
if(pri[i]>=n) return 1;
bignum a=powmod(pri[i],m,n);
if(a==1) continue;
int j;
for(j=0;j<k;j++)
{
if(a==n-1) break;
a=mulmod(a,a,n);
}
if(j<k) continue;
return 0;
}
return 1;
}
//pollard_rho 大整数分解,给出n的一个非1因子,返回n是为一次没有找到
bignum pollard_rho(bignum C,bignum N)
{
bignum I, X, Y, K, D;
I = 1;
X = rand() % N;
Y = X;
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 = (mulmod(X, X, N) + N - C) % N;
}while (Y != X);
return N;
}
//找出N的最小质因数
bignum rho(bignum N)
{
if (Miller_Rabin(N)) return N;
do
{
bignum T = pollard_rho(rand() % (N - 1) + 1, N);
if (T < N)
{
bignum A, B;
A = rho(T);
B = rho(N / T);
return A < B ? A : B;
}
}
while(1);
}
//N分解质因数,这里是所有质因数,有重复的
bignum AllFac[1100];
int Facnum;
void findrepeatfac(bignum n)
{
if(Miller_Rabin(n))
{
AllFac[++Facnum]=n;
return ;
}
bignum factor;
do
{
factor=pollard_rho(rand() % (n - 1) + 1, n);
}while(factor>=n);
findrepeatfac(factor);
findrepeatfac(n/factor);
}

//求N的所有质因数,是除去重复的
bignum Fac[1100];
int num[1100];
int len;
void FindFac(bignum n)
{
len=0;
//初始化
memset(AllFac,0,sizeof(AllFac));
memset(num,0,sizeof(num));
Facnum=0;
findrepeatfac(n);
sort(AllFac+1,AllFac+1+Facnum);
Fac[0]=AllFac[1];
num[0]=1;
for(int i=2;i<=Facnum;i++)
{
if(Fac[len]!=AllFac[i])
{
Fac[++len]=AllFac[i];
}
num[len]++;
}
}

//dfs将key分解成两个互质的数的乘积,并且使这两个数和最小
/*
bignum Fac[200];
int num[200];
int len;(0-len);*/
bignum res_a,res_b;
bignum _min,key,com;
void dfs(int cur,bignum val)
{
if(cur==len+1)
{
bignum a=val,b=key/val;
if(gcd(a,b)==1)
{
a*=com,b*=com;
if(a+b<_min)
{
_min=a+b;
res_a=a<b ? a : b;
res_b=a>b ? a : b;
}
}
return ;
}
bignum s=1;
for(int i=0;i<=num[cur];i++)
{
if(val*s>=_min)
{
return ;
}
dfs(cur+1,val*s);
s*=Fac[cur];
}
}
int main ()
{
srand(time(NULL));
bignum l,g;
while(scanf("%I64u%I64u",&g,&l)!=EOF)
{
if(l==g)
{
printf("%I64u %I64u/n",g,l);
continue;
}
//初始化
key=l/g;
FindFac(key);
//初始化
_min=(1<<63)-1;com=g;
dfs(0,1);
printf("%I64u %I64u/n",res_a,res_b);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: