博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ 2429 GCD & LCM Inverse ★(pollard-ρ && DFS枚举)
阅读量:5125 次
发布时间:2019-06-13

本文共 4669 字,大约阅读时间需要 15 分钟。

题目链接
题目大意:给定gcd(a,b)和lcm(a,b)(<2^63),求a和b,如果有多种情况,输出和最小的情况.   首先gcd(a,b) * lcm(a,b) = a*b,但是如果我们直接从a*b中分解因子的话,a*b是可能超过long long的,这样就不好处理了. 我们可以先把gcd(a,b)都分给a,b,因为他们的因子中都要有gcd(a,b).于是现在还剩下lcm(a,b)/gcd(a,b)了,于是我们先用pollard-rho给他分解因子. 那么还有一个问题,能随便分么?分出来的a,b虽然能保证a*b,但是能保证他们的gcd和lcm都是给定的么?不一定. 所以我们还需要注意分因数的过程中还要保证gcd和lcm的正确性. 但这个问题其实不难,因为a*b一定是不变的,所以我们只要保证gcd和lcm其中一个不变,另一个也就自然不变了.显然保证gcd比较简单. 我们知道lcm/gcd = p1^q1 * p2 ^q2 *……* pn^qn,其中p1,p2,……,pn是因子.我们只要保证某个数把某个pi全部取走,这样他们除了先前取走的gcd外再无公因数,则可保gcd正确.这样的话,2^63内的数所有不同的因子个数最多也就十几个,枚举无压力.  
#include #include #include using namespace std;//return a * b % munsigned long long mul_mod(unsigned long long a, unsigned long long b, unsigned long long m){    //为了防止long long型a * b溢出,有时需要把乘法变加法    //且因为暴力加法会超时要使用二分快速乘法模(模仿二分快速幂模……)    unsigned long long res = 0, tmp = a % m;    while(b){        if (b & 1)        {            res = res + tmp;            res = (res >= m ? res - m : res);        }        b >>= 1;        tmp <<= 1;        tmp = (tmp >= m ? tmp - m : tmp);    }    return res;}//return a ^ b % mlong long exp_mod(long long a, long long b, long long m){    long long res = 1 % m, tmp = a % m;    while(b){        if (b & 1){            //如果m在int范围内直接用下一式乘就可以,否则需要用下二式把乘法化加法,用快速乘法模            //res = (res * t) % m;            res = mul_mod(res, tmp, m);        }        //同上        //t = t * t % m;        tmp = mul_mod(tmp, tmp, m);        b >>= 1;    }    return res;}/*-------------Miller-Rabin 素数测试 部分(用到上面mul_mod和exp_mod   素数return true)--------------*/bool Miller_Rabin(long long n){    int a[5] = {2, 3, 7, 61, 24251};    //一般Miller_Rabin素数测试是随机选择100个a,这样的错误率为0.25^100    //但在OI&&ACM中,可以使用上面一组a,在这组底数下,10^16内唯一的强伪素数为46,856,248,255,981    if (n == 2)        return true;    if (n == 1 || (n & 1) == 0)        return false;    long long b = n - 1;    for (int i = 0; i < 5; i ++){        if (a[i] >= n)            break;        while((b & 1) == 0)    b >>= 1;        long long t = exp_mod(a[i], b, n);        while(b != n - 1 && t != 1 && t != n - 1){            t = mul_mod(t, t, n);            b <<= 1;        }        if (t == n - 1 || (b & 1))            continue;        else            return false;    }    return true;}/*-------------Miller-Rabin 素数测试 部分--------------*//*-------------pollard-rho 大整数n因子分解 部分(用到mul_mod()和Miller-Rabin测试)--------------*/long long factor[100];      //存n的素因子long long nfactor, minfactor;long long gcd(long long a, long long b){    return b ? gcd(b, a%b) : a;}void Factor(long long n);void pollard_rho(long long n){    if (n <= 1)        return ;    if (Miller_Rabin(n)){        factor[nfactor ++] = n;        if (n < minfactor)            minfactor = n;        return ;    }    long long x = 2 % n, y = x, k = 2, i = 1;    long long d = 1;    while(true){        i ++;        x = (mul_mod(x, x, n) + 1) % n;        d = gcd((y - x + n) % n, n);        if (d > 1 && d < n){            pollard_rho(d);            pollard_rho(n/d);            return ;        }        if (y == x){            Factor(n);            return ;        }        if (i == k){            y = x;            k <<= 1;        }    }}void Factor(long long n){    //有时候RP不好 or n太小(比如n==4就试不出来……)用下面的pollard_rho没弄出来,则暴力枚举特殊处理一下    long long d = 2;    while(n % d != 0 && d * d <= n)        d ++;    pollard_rho(d);    pollard_rho(n/d);}/*-------------pollard-rho 大整数n因子分解 部分--------------*/vector  > vfac;void find(long long n, long long &a, long long &b){    long long sum = (1LL << 62);    long long suma;    for (int i = 0; i < (1 << vfac.size()); i ++){        long long res = 1;        for (size_t k = 0; k < vfac.size(); k ++){            if (i & (1 << k)){                for (int p = 0; p < vfac[k].second; p ++){                    res *= vfac[k].first;                }            }        }        long long remain = n / res;        if (res + remain < sum){            sum = res + remain;            a = suma = res;            b = remain;        }        if (res + remain == sum){            if (res < suma){                a = suma = res;                b = remain;            }        }    }    return ;}int main(){    long long g, l, n;    while(cin >> g >> l){        n = l / g;        vfac.clear();        nfactor = 0;        pollard_rho(n);        long long tmp = n;        for(int i = 0; i < nfactor; i ++){            int facnum = 0;            while(tmp % factor[i] == 0){                tmp /= factor[i];                facnum ++;            }            vfac.push_back(make_pair(factor[i], facnum));        }        long long a, b;        find(n, a, b);        cout << a * g << " " << b * g << endl;    }    return 0;}
 

转载于:https://www.cnblogs.com/AbandonZHANG/archive/2013/01/20/4114201.html

你可能感兴趣的文章
幸运转盘v1.0 【附视频】我的Android原创处女作,请支持!
查看>>
UseIIS
查看>>
集合体系
查看>>
vi命令提示:Terminal too wide
查看>>
引用 移植Linux到s3c2410上
查看>>
MySQL5.7开多实例指导
查看>>
[51nod] 1199 Money out of Thin Air #线段树+DFS序
查看>>
Red and Black(poj-1979)
查看>>
分布式锁的思路以及实现分析
查看>>
腾讯元对象存储之文件删除
查看>>
jdk环境变量配置
查看>>
安装 Express
查看>>
包含列的索引:SQL Server索引的阶梯级别5
查看>>
myeclipse插件安装
查看>>
浙江省第十二届省赛 Beauty of Array(思维题)
查看>>
NOIP2013 提高组 Day1
查看>>
cocos2dx 3.x simpleAudioEngine 长音效被众多短音效打断问题
查看>>
存储(硬件方面的一些基本术语)
查看>>
观察者模式
查看>>
Weka中数据挖掘与机器学习系列之基本概念(三)
查看>>