题解 大数拆分 POJ 2429

题意:给出两个数的gcd和lcm 求这两个数,要求为这两个数相加是所有满足条件的数的最小的那一对。

做法:关于gcd和lcm有两个基本公式。1.a*b=gcd*lcm 2.a=k1*gcd,b=k2*gcd,c=lcm/gcd,得 k1*k2=c; 

   由公式2可得。对c进行拆分后所得所有因子,可任意分配给k1和k2.(前提是两个相同的因子不能同时给k1和    k2,否则会导致a,b不互质)

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <algorithm>
using namespace std;
typedef long long int64;
int64 gcd(int64 a,int64 b)
{
    return b==0?a:gcd(b,a%b);
}
int64 mult_mod(int64 a,int64 b,int64 c)//计算a*b%c
{
    int64 ret=0;
    int64 tmp=a;
    a%=c,b%=c;//保证a,b小于c,节约计算时间。
    while(b)
    {
        if(b&1)
        {
            ret+=tmp;
            if(ret>c)   ret-=c;
        }
        tmp<<=1;
        if(tmp>c)tmp-=c;
        b>>=1;
    }
    return ret;
}
int64 pow_mod(int64 a,int64 n,int64 mod)//计算a^n%mod
{
    int64 ret = 1;
    int64 tmp = a%mod;
    while(n)
    {
        if(n & 1)ret = mult_mod(ret,tmp,mod);
        tmp = mult_mod(tmp,tmp,mod);
        n >>= 1;
    }
    return ret;
}
bool check(int64 a,int64 n,int64 x,int64 t)//判断是不是合数
{
    int64 ret = pow_mod(a,x,n);
    int64 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;
    else return false;
}
bool Miller_Rabin(long long n,int k)//米勒罗宾(判断是不是素数)
{
    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++;}
    srand(time(NULL));
    for(int i=0;i<k;i++)
    {
        long long a = rand()%(n-1) + 1;
        if( check(a,n,x,t) )
        return false;
    }
    return true;
}
int64 factor[10000];
int tot;
int64 pollard_rho(int64 x,int64 c)//找出x的一个因子
{
    int64 i=1, k=2;
    srand(time(NULL));
    int64 x0=rand()%(x-1)+1;
    int64 y=x0;
    while(1)
    {
        i++;
        x0=(mult_mod(x0,x0,x)+c)%x;
        int64 d=gcd(y-x0+x,x);
        if(d!=1&&d!=x)return d;
        if(y==x0)return x;
        if(i==k){y=x0;k+=k;}
    }
}
void findfac(int64 n,int k)
{
    if(n==1)return;
    if(Miller_Rabin(n,10))
    {
        factor[tot++]=n;
        return;
    }
    int64 p=n;
    int c=k;
    while(p>=n)
    p=pollard_rho(p,c--);//值变化,防止死循环k
    findfac(p,k);
    findfac(n/p,k);
}
int64 mins,aa,bb;int top;
void dfs(int64 a,int64 b,int p)//将所有质数进行分配
{
    if(a+b>=mins) return;
    if(p==top)
    {
        if(a+b<mins)
        {
            mins=a+b;
            aa=a;
            bb=b;
        }
        return;
    }
    dfs(a*factor[p],b,p+1);
    dfs(a,b*factor[p],p+1);
}
int main()
{
    int64 g,l,c;
    while(~scanf("%I64d%I64d",&g,&l))
    {
        if(g==l){printf("%I64d %I64d\n",g,l);continue;};
        mins=~0ull>>1;tot=0;
        c=l/g;
        findfac(c,107);
        top=0;
        sort(factor,factor+tot);
        for(int i=0;i<tot;i++)//将相同的质数合并
        {
            if(i==0) factor[top++]=factor[i];
            else if(factor[i]==factor[i-1]) factor[top-1]*=factor[i];
            else factor[top++]=factor[i];
        }
        dfs(g,g,0);
        if(aa>bb) swap(aa,bb);
        printf("%I64d %I64d\n",aa,bb);
    }
    return 0;
}

posted on 2014-08-23 16:50  一锅土豆  阅读(169)  评论(0编辑  收藏  举报