POJ-2429 GCD & LCM Inverse

题意:给定某两个数GCD和LCM,求相加和最小的这两个数。(GCD和LCM均小雨2^63)。

思路:LCM=a*b/GCD,a/GCD*b/GCD*GCD=LCM,a/GCD*b/GCD=LCM/GCD,即先Pollard_rho法对LCM/GCD进行整数分解,然后对其因子进行深搜找出最小的结果。

题目链接:http://poj.org/problem?id=2429

 

View Code
  1 /*******************Miller_Rabin素数测试&&Pollard_rho整数分解**************************/ 
  2 #include <cstdio>
  3 #include <cmath>
  4 #include <ctime>
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <string>
  8 #include <algorithm>
  9 #include <iostream>
 10 #define Times 11
 11 #define MAX ((long long)1<<61) 
 12 #define N 501
 13 #define C 201
 14 #define LL long long
 15 using namespace std;
 16 
 17 
 18 int ct,cnt;
 19 LL mini,jl[N],factor[N],num[N];
 20 LL mina,minb,ans,n,m;
 21 
 22 LL gcd(LL a,LL b){
 23     return b==0?a:gcd(b,a%b);
 24 }
 25 
 26 LL random(LL n){
 27     return (LL)((double)rand()/RAND_MAX*n+0.5);
 28 }
 29 
 30 LL multi(LL m,LL n,LL k){
 31     LL b=0;
 32     while(n){
 33         if(n&1) b=(b+m)%k;
 34         n>>=1;
 35         m=(m<<1)%k;
 36     }
 37     return b;
 38 }
 39 
 40 LL quick_mod(LL m,LL n,LL k){
 41     LL b=1;
 42     m%=k; 
 43     while(n){
 44         if(n&1) b=multi(b,m,k);
 45         n/=2;
 46         m=multi(m,m,k);
 47     }
 48     return b;
 49 }
 50 
 51 bool Witness(LL a,LL n){
 52     LL m=n-1;
 53     int j=0;
 54     while(!(m&1)){
 55         j++;
 56         m>>=1;
 57     }
 58     LL x=quick_mod(a,m,n);
 59     if(x==1||x==n-1) return false;
 60     while(j--){
 61         x=x*x%n;
 62         if(x==n-1) return false;
 63     }
 64     return true;
 65 }
 66 
 67 bool Miller_Rabin(LL n){
 68     if(n<2) return false;
 69     if(n==2) return true;
 70     if(!(n&1)) return false;
 71     for(int i=1;i<=Times;i++){
 72         LL a=random(n-2)+1;
 73         if(Witness(a,n)) return false;
 74     }
 75     return true;
 76 }
 77 
 78 LL Pollard_rho(LL n,int c){
 79     LL x,y,d,i=1,k=2;
 80     x=random(n-1)+1;
 81     y=x;
 82     while(1){
 83         i++;
 84         x=(multi(x,x,n)+c)%n;
 85         d=gcd(y-x,n);
 86         if(1<d&&d<n) return d;
 87         if(y==x) return n;
 88         if(i==k){
 89             y=x;
 90             k<<=1;
 91         }
 92     }
 93 }
 94 
 95 void find(LL n,int k){
 96     if(n==1) return ;
 97     if(Miller_Rabin(n)){
 98         jl[++ct]=n;
 99         return ;
100     }
101     LL p=n;
102     while(p>=n) p=Pollard_rho(p,k--);
103     find(p,k);
104     find(n/p,k);
105 }
106 
107 void dfs(LL c,LL value){
108     LL s=1,a,b;
109     if(c==cnt+1){
110         a=value;
111         b=ans/a;
112         if(gcd(a,b)==1){
113             a*=n;
114             b*=n;
115             if(a+b<mini){
116                 mini=a+b;
117                 mina=a; minb=b;
118             }
119         }
120         return ;
121     }
122     for(LL i=0;i<=num[c];i++){
123         if(s*value>mini) return ;
124         dfs(c+1,s*value);
125         s*=factor[c];
126     }
127 }
128 
129 int main(){
130     
131 //    freopen("data.in","r",stdin);
132 //    freopen("data.out","w",stdout);
133     
134 //    srand(time(NULL));  
135     while(scanf("%lld%lld",&n,&m)!=EOF){
136         if(n==m) {printf("%lld %lld\n",n,m); continue;}
137         mini=MAX;
138         ct=cnt=0;
139         ans=m/n; 
140         find(ans,C);
141         sort(jl+1,jl+ct+1);
142         memset(factor,0,sizeof(factor));
143         memset(num,0,sizeof(num));
144         num[0]=1;
145         factor[0]=jl[1];
146         for(int i=2;i<=ct;i++){
147             if(jl[i]!=jl[i-1]) factor[++cnt]=jl[i];
148             num[cnt]++;
149         }
150         dfs(0,1);
151         if(mina>minb) swap(mina,minb);
152         printf("%lld %lld\n",mina,minb);
153     }
154     return 0;
155 }

转载于:https://www.cnblogs.com/Hug-Sea/articles/2625630.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值