poj 2429 GCD & LCM Inverse (pollard

来源:互联网 发布:同轴圆柱形电容器算法 编辑:程序博客网 时间:2024/06/16 05:59

已知两个数的gcd和lcm要求出当两个数的和最小的时候的两个数。

思路:lcm = x * y / gcd, -> lcm/ gcd = x / gcd   * y / gcd.另a = x /gcd, b = y /gcd,c = lcm/gcd.那么a和b两个数互质,否则的话x 和 y的gcd就会更大。

            现在就相当于求两个互质的数相乘得出c ,然后求这两个数相加和最小。

           思路为对c进行素数分解,不过这个时候这个数10^18特别大,得用上pollard-rho进行大数的素数分解,不过分解出来的素数会重复,这个地方得特别注意。

           分解完成之后,就是每种素数a取或者b取,否则的话就会造成gcd不是原题中的gcd,取得过程用dfs实现,,,当初没用dfs,一直WA,痛>_<


#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<vector>#include<algorithm>#include<map>using namespace std;const int maxn = 1000000 + 10;#define INF 0x3f3f3f3f#define clr(x,y) memset(x,y,sizeof x )typedef long long ll;#define eps 10e-10const ll Mod = 1000000007;typedef pair<ll, ll> P;//ll Mult_mod (ll a,ll b,ll c)   //  a,b,c <2^63//{//    a%=c;//    b%=c;//    ll ret=0;//    while (b)//    {//        if (b&1) {ret+=a;ret%=c;}//        a<<=1;//        if (a>=c)a%=c;//        b>>=1;//    }//    return ret;//}ll Mult_mod (ll a,ll b,ll c)  //减法实现比取模速度快{    //返回(a*b) mod c,a,b,c<2^63a%=c;b%=c;ll ret=0;while (b){if (b&1){ret+=a;if (ret>=c) ret-=c;}a<<=1;if (a>=c) a-=c;b>>=1;}return ret;}//计算  x^n %cll Pow_mod (ll x,ll n,ll mod) //x^n%c{    if (n==1) return x%mod;    x%=mod;    ll tmp=x;    ll 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,不一定返回falsebool Check (ll a,ll n,ll x,ll t){    ll ret=Pow_mod(a,x,n);    ll last=ret;    for (ll 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;ll S = 20;bool Miller_Rabin (ll n){    if (n<2) return false;    if (n==2) return true;    if ((n&1)==0) return false;//偶数    ll x=n-1;    ll t=0;    while ((x&1)==0) {x>>=1;t++;}    for (ll i=0;i<S;i++)    {        ll a=rand()%(n-1)+1; //rand()需要stdlib.h头文件        if (Check(a,n,x,t))            return false;//合数    }    return true;}//************************************************//pollard_rho 算法进行质因数分解//************************************************ll factor[maxn];//质因数分解结果(刚返回时是无序的)ll tol;//质因数的个数。数组下标从0开始ll Gcd (ll a,ll b){    if (a==0) return 1;  //???????    if (a<0) return Gcd(-a,b);    while (b)    {        ll t=a%b;        a=b;        b=t;    }    return a;}ll Pollard_rho (ll x,ll c){    ll i=1,k=2;    ll x0=rand()%x;    ll y=x0;    while (true)    {        i++;        x0=(Mult_mod(x0,x0,x)+c)%x;        ll 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 (ll n){    if (Miller_Rabin(n)) //素数    {        factor[tol++]=n;        return;    }    ll p=n;    while (p>=n) p=Pollard_rho(p,rand()%(n-1)+1);    Findfac(p);    Findfac(n/p);}ll lcm,gcd;ll a[maxn];ll b[maxn];ll len;void Init(ll n){    len = 0;    for(ll i = 0; i < tol && factor[i] <= n; i ++)//所有的素数因子的积    {        a[i] = 0;        b[len] = 1;        while(n % factor[i] == 0)        {            b[len] *= factor[i];           a[i] ++;           n /= factor[i];        }        if(b[len] > 1)            len ++;    }}ll xs,ys;ll maxs,temps;void dfs(ll x,ll y,ll pos)//dfs找最小{    if(pos == len)    {        if(x + y < maxs)            maxs = x + y,temps = x;        return ;    }    dfs(x,y * b[pos],pos + 1);    dfs(x * b[pos],y,pos+1);}int main(){    while( ~ scanf("%lld%lld",&gcd,&lcm))    {        if(lcm == 0)        {            printf("0 %lld\n",gcd);            continue;        }        if(lcm / gcd == 1)        {            printf("%lld %lld\n",gcd,gcd);            continue;        }        tol = 0;        Findfac(lcm/gcd);        sort(factor,factor + tol);        Init(lcm/gcd);        sort(b,b + len);        maxs = lcm/gcd/b[0] + b[0],temps = b[0];        dfs(1,1,0);        ll x = temps,y = maxs - temps;        if(x > y)        {            ll ts = x;            x = y;            y = ts;        }        printf("%lld %lld\n",x * gcd,y * gcd);    }    return 0;}


原创粉丝点击