POJ/PKU 2429 GCD & LCM

  题目说给出最大公约数和最小公倍数,求a,b。如果存在多个解取最小a+b。

  思路很简单,a/GCD和b/GCD是互质的,所以a/GCD和b/GCD分解以后产生的因子肯定不同。所以他们的乘积a/GCD*(b/GCD)=a*b/GCD/GCD=LCM/GCD因数分解以后产生的任何一种质因数只能属于a/GCD或b/GCD。很明显种数不会超过15,深搜或者位运算很容易求出所有组合,取其中a+b最小的a,b即可。

  质因数分解直接用PollardRho的模板,但是在G++下仍然会re,可能是编译器的原因。

/*
 * File:   main.cpp
 * Author: acmer
 *
 * Created on June 11, 2011, 3:55 PM
 */

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <algorithm>

using namespace std;

#define Random(n) (rand()%(n+1))

typedef __int64 int64;

const int kMaxT(50);

int cnt;
int64 factor[207];

int64 Gcd(int64 a,int64 b){
    for(int64 t=a%b;t;a=b,b=t,t=a%b);
    return b>0?b:(b*(-1));
}

int64 MutiMod(int64 a,int64 b,int64 n){
    int64 exp(a%n),res(0);
    while(b){
        if(b&1){
            res+=exp;
            if(res>n)res-=n;
        }
        exp<<=1;
        if(exp>n)exp-=n;
        b>>=1;
    }
    return res;
}

int64 ExpMod(int64 a,int64 n,int64 b){
    int64 r(1),t(a%b);
    if(n==0) return 1%b;
    while(n>1){
        if(n&1)
            r=MutiMod(r,t,b);
        t=MutiMod(t,t,b);
        n>>=1;
    }
    return MutiMod(r,t,b);
}

bool MillerRabbin(int64 n){
    if(n==2)
        return true;
    if(n<2 || !(n&1))
        return false;
    int64 a,u(n-1),x,y;
    int t(0);
    while(u%2==0){
        t++;
        u>>=1;
    }
    srand(time(NULL));
    for(int i=1;i<=kMaxT;i++){
        a=Random(n-2)+1;
        x=ExpMod(a,u,n);
        for(int j=0;j<t;j++){
            y=MutiMod(x,x,n);
            if(y==1 && x!=1 && x!=n-1)
                return false;
            x=y;
        }
        if(y!=1)
            return false;
    }
    return true;
}

int64 PollardRho(int64 n,int c){
    int64 x(Random(n-2)+1),y(x),d,i(1),k(2);
    while (true){
        i++;
        x=(MutiMod(x,x,n)+c)%n;
        d=Gcd(y-x,n);
        if(d > 1 && d < n)
            return d;
        if(x==y)
            return n;
        if(i==k){
            y=x;
            k<<=1;
        }
    }
}

int64 temp;

//找出所有质因数
void FindFactor(int64 n, int k){
    if(n == 1)
        return;
    if(MillerRabbin(n)){
        //保存小于n的所有质因数
        if (n != temp){
            factor[cnt++] = n;
        }
        return;
    }
    int64 p(n);
    while (p >= n)
        p = PollardRho(p,k--);
    FindFactor(p, k);
    FindFactor(n/p,k);
}

int l;
int64 t[67], minf, a, n;

//求最小的a+b
void dfs(int i, int64 sum){
    if (i == l + 1){
        if (minf > (sum + n / sum)){
            minf = sum + n / sum;
            a = sum;
        }
        return;
    }
    dfs(i+1, sum * t[i]);
    dfs(i+1, sum * 1);
    return;
}

int main(){

    int64 LCM, GCD;

    while (cin>>GCD>>LCM){

        n = LCM / GCD;
        if (n == 1 || MillerRabbin(n)){
            cout<<GCD<<" "<<LCM<<endl;
            continue;
        }

        cnt = 0;
        temp = n;

        FindFactor(n, 107);
        sort(factor, factor + cnt);

        l = 0;
        t[l] = factor[0];
        int j = 0;
        for (int i = 1; i < cnt; i++)
            if (factor[i] == factor[j])
                t[l] *= factor[i];
            else {
                t[++l] = factor[i];
                j = i;
            }
        minf = 2e63;//科学计数法越界以后会自动换为此范围内最大数
        dfs(0, 1);

        cout<<min(a*GCD, LCM/a)<<" "<<max(a*GCD, LCM/a)<<endl;
    }
    return 0;
}

posted @ 2011-08-29 08:50  like@neu  阅读(227)  评论(0编辑  收藏  举报