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 }

猜你喜欢

转载自www.cnblogs.com/fzl194/p/9058490.html