POJ 2429 GCD & LCM Inverse(素数判定Miller-Rabin+素因子分解Pollard-rho+二进制枚举)

GCD & LCM Inverse

Time Limit: 2000MS

 

Memory Limit: 65536K

Total Submissions: 18825

 

Accepted: 3486

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

Source

POJ Achilles

算法分析:

题意:
给出gcd(a,b)lcm(a,b),求ab,如果存在多组方案则输出a+b最小的那一组
分析:
首先,我们可以看出(x/gcd)*(y/gcd)=lcm/gcd,并且x/gcdy/gcd互质,那么我们先利用把所有的质数求出来Pollard_Rho,将相同的质数合并,现在的问题转变成把合并后的质数分为两堆,使得x+y最小,然后我们可以采用二进制枚举(解释点这里),一个个枚举出来。

代码实现:

#include<cstdio>  
#include<cstring>  
#include<cstdlib>  
#include<cctype>  
#include<cmath>  
#include<iostream>  
#include<sstream>  
#include<iterator>  
#include<algorithm>  
#include<string>  
#include<vector>  
#include<set>  
#include<map>  
#include<stack>  
#include<deque>  
#include<queue>  
#include<list>  
using namespace std;
 
 
//****************************************************************
// Miller_Rabin 算法进行素数测试
//速度快,而且可以判断 <2^63的数
//****************************************************************
const int S=20;//随机算法判定次数,S越大,判错概率越小
 
typedef long long ll;
//计算 (a*b)%c.   a,b都是long long的数,直接相乘可能溢出的
//  a,b,c <2^63
long long mult_mod(long long a,long long b,long long c)       //快速乘计算   (a*b)%c
{
    a%=c;
    b%=c;
    long long ret=0;
    while(b)
    {
        if(b&1){ret+=a;ret%=c;}
        a<<=1;
        if(a>=c)a%=c;
        b>>=1;
    }
    return ret;
}
 
 
 
//计算  x^n %c  把快速幂分成这两部分写的好处,可以防止数越界
long long pow_mod(long long x,long long n,long long mod)//快速幂 计算  x^n%c
{
    if(n==1)return x%mod;
    x%=mod;
    long long tmp=x;
    long long ret=1;
    while(n)
    {
        if(n&1) ret=mult_mod(ret,tmp,mod);
        tmp=mult_mod(tmp,tmp,mod);
        n>>=1;
    }
    return ret;
}
 
 
 
 
 
//以a为基,n-1=x*2^t      a^(n-1)=1(mod n)  验证n是不是合数
//一定是合数返回true,不一定返回false
bool check(long long a,long long n,long long x,long long t)
{
    long long ret=pow_mod(a,x,n);
    long long last=ret;
    for(int i=1;i<=t;i++)
    {
        ret=mult_mod(ret,ret,n);
        if(ret==1&&last!=1&&last!=n-1) return true;//合数
        last=ret;
    }
    if(ret!=1) return true;
    return false;
}
 
// Miller_Rabin()算法素数判定
//是素数返回true.(可能是伪素数,但概率极小)
//合数返回false;
 
bool Miller_Rabin(long long n)
{
    if(n<2)return false;
    if(n==2)return true;
    if((n&1)==0) return false;//偶数
    long long x=n-1;
    long long t=0;
    while((x&1)==0){x>>=1;t++;}
    for(int i=0;i<S;i++)
    {
        long long a=rand()%(n-1)+1;//rand()需要stdlib.h头文件
        if(check(a,n,x,t))
            return false;//合数
    }
    return true;
}
 
 
//************************************************
//pollard_rho 算法进行质因数分解
//************************************************
long long factor[11100];//质因数分解结果(刚返回时是无序的)
long long x[1100];
int tol;//质因数的个数。数组小标从0开始
 
long long gcd(long long a,long long b)
{
    if(a==0)return 1;//???????
    if(a<0) return gcd(-a,b);
    while(b)
    {
        long long t=a%b;
        a=b;
        b=t;
    }
    return a;
}
 
long long Pollard_rho(long long x,long long c)
{
    long long i=1,k=2;
    long long x0=rand()%x;
    long long y=x0;
    while(1)
    {
        i++;
        x0=(mult_mod(x0,x0,x)+c)%x;
        long long d=gcd(y-x0,x);
        if(d!=1&&d!=x) return d;
        if(y==x0) return x;
        if(i==k){y=x0;k+=k;}
    }
}
//对n进行素因子分解
void findfac(long long n)
{
    if(Miller_Rabin(n))//素数
    {
        factor[tol++]=n;
        return;
    }
    long long p=n;
    while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1);
    findfac(p);
    findfac(n/p);
}
 
int main()
{
    //srand(time(NULL));//需要time.h头文件//POJ上G++不能加这句话
    long long g,lcm;
    while(scanf("%I64d%I64d",&g,&lcm)!=EOF)
    {
    	 if (g == lcm)
        {
            printf("%lld %lld\n",g,lcm);
            continue;
        }

		ll ans=lcm/g;
        tol=0; 
        findfac(ans);
      
       
		sort (factor, factor + tol); //fac保存的是ans的素因子,比如3 60对应的fac数组是2 2 5
 
       int  k = 0;
        x[0] = factor[0];
        for (int i =1; i<tol; ++i)
        {
            if (factor[i] == factor[i - 1]) x[k] *= factor[i];
            else x[++k] = factor[i];
        }
        sort (x, x + k + 1); //x保存的是所有不相同的素因子,比如3 60 对应的x数组是4 5
        
        
	    ll n=1e18,a=1,b=ans;
	        k++;
        int all = (1<<k);
   
        for(int i=0; i<all; i++)
		{
             ll tx=1,ty;
            for(int j=0;j<k;j++)
                if(i&(1<<j))tx*=x[j];
            ty=ans/tx;
            if(tx<ty&&n>tx+ty)
                n=tx+ty,a=tx,b=ty;
            
        }
            
      printf("%lld %lld\n",a*g,b*g);;
       
       
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sdz20172133/article/details/81474609