题意:给定某两个数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 }