• 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 }
  • 相关阅读:

    如何找回自己!
    身体锻炼靶心心率!
    圣人言大任之人!
    如何修清净心?(净空老法师法语)
    vim 查询定位!
    深切悼念灾区遇难同胞!
    求后倒零
    植物大战僵尸【二分答案, 加贪心思想】
    植物大战僵尸【二分答案, 加贪心思想】
  • 原文地址:https://www.cnblogs.com/fzl194/p/9058490.html
Copyright © 2020-2023  润新知