POJ2429 GCD & LCM Inverse pollard_rho大整数分解
Given two positive integers a and b, we can easily calculate the greatest common divisor (GCD) and the least common multiple (LCM) of a and b. But what about the inverse? That is: given GCD and LCM, finding a and b.
Input
The input contains multiple test cases, each of which contains two positive integers, the GCD and the LCM. You can assume that these two numbers are both less than 2^63.
Output
For each test case, output a and b in ascending order. If there are multiple solutions, output the pair with smallest a + b.
Sample Input
3 60
Sample Output
12 15
题意:给出两个数的最大公约数和最小公倍数,让你找出满足条件的两个数,使他们的和最小。
题解:
对于两个数a,b和他们的最大公约数gcd以及最小公倍数lcm,有lcm=a*b/gcd,进一步变形可以得到:(a/gcd * b/gcd)*gcd=lcm,即(a/gcd * b/gcd)=lcm/gcd,我们令m=a/gcd,n=b/gcd,那么问题就变为了:找出两个互素的整数,使他们的乘积为key=lcm/gcd。我们可以用Pollard_rho算法进行质因素分解的方法找出lcm/gcd的所有素因子,然后dfs找出任意几个素数因子之积(设为x),设y=key/x,找出最小的x+y就行了
代码:
1 #include <cstdio> 2 3 #include <iostream> 4 5 #include <cstdlib> 6 7 #include <cmath> 8 9 #include <algorithm> 10 11 12 13 #define times 10 14 15 #define N 501 16 17 using namespace std; 18 19 typedef unsigned long long LL; 20 21 const LL INF=(LL)1<<61; 22 23 LL key,ct,cnt,gd,lm,resa,resb,mini; 24 25 LL fac[N],num[N]; 26 27 28 29 LL gcd(LL a,LL b) 30 31 { 32 33 return b?gcd(b,a%b):a; 34 35 } 36 37 38 39 LL multi(LL a,LL b,LL m) 40 41 { 42 43 LL ans=0; 44 45 a%=m; 46 47 while(b) 48 49 { 50 51 if(b&1) 52 53 { 54 55 ans=(ans+a)%m; 56 57 b--; 58 59 } 60 61 b>>=1; 62 63 a=(a+a)%m; 64 65 } 66 67 return ans; 68 69 } 70 71 72 73 LL quick_mod(LL a,LL b,LL m) 74 75 { 76 77 LL ans=1; 78 79 a%=m; 80 81 while(b) 82 83 { 84 85 if(b&1) 86 87 { 88 89 ans=multi(ans,a,m); 90 91 b--; 92 93 } 94 95 b>>=1; 96 97 a=multi(a,a,m); 98 99 } 100 101 return ans; 102 103 } 104 105 106 107 bool Miller_Rabin(LL n) 108 109 { 110 111 if(n==2) return true; 112 113 if(n<2||!(n&1)) return false; 114 115 LL m=n-1; 116 117 int k=0; 118 119 while(!(m&1)) 120 121 { 122 123 k++; 124 125 m>>=1; 126 127 } 128 129 for(int i=0;i<times;i++) 130 131 { 132 133 LL a=rand()%(n-1)+1; 134 135 LL x=quick_mod(a,m,n); 136 137 LL y=0; 138 139 for(int j=0;j<k;j++) 140 141 { 142 143 y=multi(x,x,n); 144 145 if(y==1&&x!=1&&x!=n-1) return false; 146 147 x=y; 148 149 } 150 151 if(y!=1) return false; 152 153 } 154 155 return true; 156 157 } 158 159 160 161 LL Pollard_rho(LL n,LL c) 162 163 { 164 165 LL i=1,k=2; 166 167 LL x=rand()%(n-1)+1; 168 169 LL y=x; 170 171 while(true) 172 173 { 174 175 i++; 176 177 x=(multi(x,x,n)+c)%n; 178 179 LL d=gcd((y-x+n)%n,n); 180 181 if(1<d&&d<n) return d; 182 183 if(y==x) return n; 184 185 if(i==k) 186 187 { 188 189 y=x; 190 191 k<<=1; 192 193 } 194 195 } 196 197 } 198 199 200 201 void Find(LL n,LL c) 202 203 { 204 205 if(n==1) return ; 206 207 if(Miller_Rabin(n)) 208 209 { 210 211 fac[ct++]=n; 212 213 return ; 214 215 } 216 217 LL p=n; 218 219 LL k=c; 220 221 while(p>=n) p=Pollard_rho(p,c--); 222 223 Find(p,k); 224 225 Find(n/p,k); 226 227 } 228 229 230 231 void dfs(LL dept,LL product) 232 233 {//dept为递归深度,product为其中一个因子 234 235 if(dept==cnt) 236 237 { 238 239 LL a=product; 240 241 LL b=key/a; 242 243 if(gcd(a,b)==1) 244 245 { 246 247 a*=gd; 248 249 b*=gd; 250 251 if(a+b<mini) 252 253 { 254 255 mini=a+b; 256 257 resa=a; 258 259 resb=b; 260 261 } 262 263 } 264 265 return ; 266 267 } 268 269 for(int i=0;i<=num[dept];i++) 270 271 { 272 273 if(product>mini) return ; 274 275 dfs(dept+1,product); 276 277 product*=fac[dept]; 278 279 } 280 281 } 282 283 284 285 286 287 void Solve(LL n) 288 289 { 290 291 ct=0; 292 293 Find(n,120); 294 295 sort(fac,fac+ct); 296 297 num[0]=1; 298 299 int k=1; 300 301 for(int i=1;i<ct;i++) 302 303 { 304 305 if(fac[i]==fac[i-1]) 306 307 num[k-1]++; 308 309 else 310 311 { 312 313 num[k]=1; 314 315 fac[k++]=fac[i]; 316 317 } 318 319 } 320 321 cnt=k; 322 323 dfs(0,1); 324 325 if(resa>resb) swap(resa,resb); 326 327 } 328 329 330 331 int main() 332 333 { 334 335 while(cin>>gd>>lm) 336 337 { 338 339 if(gd==lm) 340 341 { 342 343 printf("%llu %llu\n",gd,lm); 344 345 continue; 346 347 } 348 349 mini=INF; 350 351 key=lm/gd; 352 353 Solve(key); 354 355 printf("%llu %llu\n",resa,resb); 356 357 } 358 359 return 0; 360 361 }