GCD and LCM Aizu - 0005(辗转相除)+GCD & LCM Inverse POJ - 2429(java或【Miller Rabin素数測试】+【Pollar Rho整数分解】)

题目:GCD and LCM Aizu - 0005

Write a program which computes the greatest common divisor (GCD) and the least common multiple (LCM) of given a and b.

Input

Input consists of several data sets. Each data set contains a and b separated by a single space in a line. The input terminates with EOF.

Constraints
0 < a, b ≤ 2,000,000,000
LCM(a, b) ≤ 2,000,000,000
The number of data sets ≤ 50

Output

For each data set, print GCD and LCM separated by a single space in a line.

Sample Input

8 6
50000000 30000000

Output for the Sample Input

2 24
10000000 150000000

分析:

求最大公约数和最小公倍数。。。

AC代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
ll n,m;
ll gcd(ll x,ll y)
{
    return y==0?x:gcd(y,x%y);
}
int main()
{
    while(~scanf("%lld%lld",&n,&m))
    {
        ll a=gcd(n,m);
        printf("%lld %lld\n",a,n*m/a);
    }
    return 0;
}

题意:

给你两个数a和b的最大公约数和最小公倍数。求a和b(当中在满足条件的情况下。使a+b尽量小)

题目: LCM Inverse POJ - 2429

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

分析:

作者显然高估了读者的数学修养,我对数论一点都不熟悉,这题光靠前面介绍的一点数论皮毛无从下手,还是看了人家的代码才知道要用Rabin-Miller强伪素数测试和Pollard r因数分解算法。
基本思路是
(1)、(a / gcd) * (b / gcd) = lcm / gcd ,所以需要分解lcm / gcd 。将其分解为互质的两个数,如果这两个数之和最小,那么乘上gcd就是所求的答案。
(2)、但是题目数据太大,需要一个高效的素数检测算法,所以采用Rabin-Miller强伪素数测试
(3)、然后分解成质因子的n次方之积,从这些n次方中挑选一些作为x,剩下的作为y。枚举x和y的所有可能,找出最小值。
Rabin-Miller强伪素数测试和Pollard r因数分解算法

AC代码:

此代码并非我所写,我只理解了,由于时间紧迫,若有时间,回来钻研,这里放AC模板。

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<math.h>
#include<algorithm>
using namespace std;
typedef long long ll;
#define MAX_VAL (pow(2.0,60))
//miller_rabbin素性測试
ll mod_mul(ll x,ll y,ll mo)
{
    ll t,T,a,b,c,d,e,f,g,h,v,ans;
    T = (ll)(sqrt(double(mo)+0.5));
    t = T*T - mo;
    a = x / T;
    b = x % T;
    c = y / T;
    d = y % T;
    e = a*c / T;
    f = a*c % T;
    v = ((a*d+b*c)%mo + e*t) % mo;
    g = v / T;
    h = v % T;
    ans = (((f+g)*t%mo + b*d)% mo + h*T)%mo;
    while(ans < 0)
        ans += mo;
    return ans;
}

ll mod_exp(ll num,ll t,ll mo)
{
    ll ret = 1, temp = num % mo;
    for(; t; t >>=1,temp=mod_mul(temp,temp,mo))
        if(t & 1)
            ret = mod_mul(ret,temp,mo);

    return ret;
}

bool miller_rabbin(ll n)
{
    if(n == 2)
        return true;
    if(n < 2 || !(n&1))
        return false;
    int t = 0;
    ll a,x,y,u = n-1;
    while((u & 1) == 0)
    {
        t++;
        u >>= 1;
    }
    for(int i = 0; i < 50; i++)
    {
        a = rand() % (n-1)+1;
        x = mod_exp(a,u,n);
        for(int j = 0; j < t; j++)
        {
            y = mod_mul(x,x,n);
            if(y == 1 && x != 1 && x != n-1)
                return false;
            x = y;
        }
        if(x != 1)
            return false;
    }
    return true;
}
//PollarRho大整数因子分解
ll minFactor;
ll gcd(ll a,ll b)
{
    if(b == 0)
        return a;
    return gcd(b, a % b);
}

ll PollarRho(ll n, int c)
{
    int i = 1;
    srand(time(NULL));
    ll x = rand() % n;
    ll y = x;
    int k = 2;
    while(true)
    {
        i++;
        x = (mod_exp(x,2,n) + c) % n;
        ll d = gcd(y-x,n);
        if(1 < d && d < n)
            return d;
        if(y == x)
            return n;
        if(i == k)
        {
            y = x;
            k *= 2;
        }
    }
}
ll ans[1100],cnt;
void getSmallest(ll n, int c)
{
    if(n == 1)
        return;
    if(miller_rabbin(n))
    {
        ans[cnt++] = n;
        return;
    }
    ll val = n;
    while(val == n)
        val = PollarRho(n,c--);
    getSmallest(val,c);
    getSmallest(n/val,c);
}
ll a,b,sq;
void choose(ll s,ll val)
{
    if(s >= cnt)
    {
        if(val > a && val <= sq)
            a = val;
            return;
    }
    choose(s+1,val);
    choose(s+1,val*ans[s]);
}

int main()
{
    int T;
    ll G,L;
    while(~scanf("%lld%lld",&G,&L))
    {
        if(L == G)
        {
            printf("%lld %lld\n",G,L);
            continue;
        }
        L /= G;
        cnt = 0;
        getSmallest(L,200);
        sort(ans, ans+cnt);
        int j = 0;
        for(int i = 1; i < cnt; i++)
        {
            while(ans[i-1] == ans[i] && i < cnt)
                ans[j] *= ans[i++];
            if ( i < cnt )
                ans[++j] = ans[i];
        }
        cnt = j+1;
        a = 1;
        sq = (ll)sqrt(L+0.0);
        choose(0,1);
        printf("%lld %lld\n",a*G,L/a*G);
    }
    return 0;
}


JAVA

import java.util.Scanner;

public class Main
{
    static long gcd(long a,long b)
    {
        long tmp;
        while (b!=0)
        {
            tmp = b;
            b = a % b;
            a = tmp;
        }
        return a;
    }
    public static  void main(String args[])
    {
        Scanner cin = new Scanner(System.in);
        long a,b,c,i;
        while (cin.hasNext())
        {
            a = cin.nextLong();
            b = cin.nextLong();
            c = b/a;
            for(i=(long)Math.sqrt(c); i>=1; i--)
            {
                if(c%i==0&&gcd(i,c/i)==1)
                {
                    System.out.println((a*i)+" "+(b/i));
                    break;
                }
            }
        }
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值