POJ-2429 GCD & LCM Inverse---给出gcd和lcm求原来两个数
题目链接:
https://cn.vjudge.net/problem/POJ-2429
题目大意:
给出两个数的gcd和lcm,求原来的这两个数(限定两数之和最小)。
解题思路:
首先,知道gcd和lcm求原来的两个数,需要分解lcm / gcd 。将其分解为互质的两个数。
首先将lcm/gcd质因数分解,要分解出沪互质两个数字,那么这两个数字的gcd=1,也就是没有公共的质因子,所以可以直接枚举这两个数字的质因子,如果一个数要取这个质因子,就把它的指数全部取掉。
质因数分解用大数因式分解来做。
分成两个互质的数字可以用二进制枚举子集,1表示取这个质因数,0表示不取,最终求出最小的和的两个数。
1 #include<iostream> 2 #include<ctime> 3 #include<algorithm> 4 #include<map> 5 #define INF 1000000000000000009 6 using namespace std; 7 typedef long long ll; 8 map<ll, int>m; 9 const int mod = 10000019; 10 const int times = 50;//测试50次 11 ll mul(ll a, ll b, ll m) 12 //求a*b%m 13 { 14 ll ans = 0; 15 a %= m; 16 while(b) 17 { 18 if(b & 1)ans = (ans + a) % m; 19 b /= 2; 20 a = (a + a) % m; 21 } 22 return ans; 23 } 24 ll pow(ll a, ll b, ll m) 25 //a^b % m 26 { 27 ll ans = 1; 28 a %= m; 29 while(b) 30 { 31 if(b & 1)ans = mul(a, ans, m); 32 b /= 2; 33 a = mul(a, a, m); 34 } 35 ans %= m; 36 return ans; 37 } 38 bool Miller_Rabin(ll n, int repeat)//n是测试的大数,repeat是测试重复次数 39 { 40 if(n == 2 || n == 3)return true;//特判 41 if(n % 2 == 0 || n == 1)return false;//偶数和1 42 43 //将n-1分解成2^s*d 44 ll d = n - 1; 45 int s = 0; 46 while(!(d & 1)) ++s, d >>= 1; 47 //srand((unsigned)time(NULL));在最开始调用即可 48 for(int i = 0; i < repeat; i++)//重复repeat次 49 { 50 ll a = rand() % (n - 3) + 2;//取一个随机数,[2,n-1) 51 ll x = pow(a, d, n); 52 ll y = 0; 53 for(int j = 0; j < s; j++) 54 { 55 y = mul(x, x, n); 56 if(y == 1 && x != 1 && x != (n - 1))return false; 57 x = y; 58 } 59 if(y != 1)return false;//费马小定理 60 } 61 return true; 62 } 63 ll gcd(ll a, ll b) 64 { 65 return b == 0 ? a : gcd(b, a % b); 66 } 67 ll pollard_rho(ll n, ll c)//找到n的一个因子 68 { 69 ll x = rand() % (n - 2) + 1; 70 ll y = x, i = 1, k = 2; 71 while(1) 72 { 73 i++; 74 x = (mul(x, x, n) + c) + n;//不断调整x2 75 ll d = gcd(y - x, n); 76 if(1 < d && d < n) 77 return d;//找到因子 78 if(y == x) 79 return n;//找到循环,返回n,重新来 80 if(i == k)//一个优化 81 { 82 y = x; 83 k <<= 1; 84 } 85 } 86 } 87 void Find(ll n, ll c) 88 { 89 if(n == 1)return;//递归出口 90 91 if(Miller_Rabin(n, times))//如果是素数,就加入 92 { 93 m[n]++; 94 return; 95 } 96 97 ll p = n; 98 while(p >= n) 99 p = pollard_rho(p, c--);//不断找因子,知道找到为止,返回n说明没找到 100 101 Find(p, c); 102 Find(n / p, c); 103 } 104 ll pow2(ll a, ll b) 105 { 106 ll ans = 1; 107 while(b) 108 { 109 if(b & 1)ans *= a; 110 b /= 2; 111 a *= a; 112 } 113 return ans; 114 } 115 int main() 116 { 117 ll x, y; 118 ll a[100], b[100]; 119 //srand((unsigned)time(NULL)); 120 while(cin >> x >> y) 121 { 122 m.clear(); 123 y = y / x; 124 Find(y, 180);//这是自己设置的一个数 125 map<ll, int>::iterator it = m.begin(); 126 for(int i = 0; it != m.end(); it++, i++) 127 { 128 a[i] = it->first; 129 b[i] = it->second; 130 } 131 ll Max = INF, ansa, ansb; 132 int t = m.size(); 133 for(int i = 0; i < (1<<t); i++) 134 { 135 ll tot = 1; 136 for(int j = 0; j < t; j++) 137 { 138 if(i & (1<<j)) 139 tot *= pow2(a[j], b[j]); 140 } 141 ll cnt = tot + y / tot; 142 if(cnt < Max) 143 { 144 Max = cnt; 145 ansa = tot; 146 ansb = y / tot; 147 } 148 } 149 if(ansa > ansb)swap(ansa, ansb); 150 cout<<ansa*x<<" "<<ansb*x<<endl; 151 } 152 return 0; 153 }
越努力,越幸运