zoukankan      html  css  js  c++  java
  • 阶乘 -> 求n!质因数因子个数 数论

    思路:题目的意思我就不再多说了 我们来介绍一下用二分法如何解

    对于二分法,我们要先明确将哪个量进行二分,然后再确定该变量的左右范围。

    对于本题,我们将我们要求的值,也就是对n进行二分,接下来,我来介绍一下具体的思路:
    首先,我们将输入的p进行质因数分解,为什么?

    因为满足条件的n!可能十分大,如果不对它进行质因数分解的话,那你就得算出n!,被T风险不说,还可能爆掉。

    如何理解上面这句话 比如 p=8, 分解质因数的话 发现8=23 即质因数为2 如果求一个最小的n!使得为8的倍数 ,就可以理解为 n! 中能至少分解出3个2 所以由此我们展开二分的思路

    来看这个代码就是进行质因数分解的,我们的目的是统计出它的质因数(用primes数组)和对应的质因数的个数(用num数组),如:
    primes[1]表示的是第一个质因数,num[1]表示第一个质因数的个数。其实可以用容器的 unordered_map<int,int>的,但考虑到蓝桥杯不能使用 所以我们尽量构建数组桶实现这种hash关系

            for (int i = 2; i <= n / i; i ++ )
                if (n % i == 0)
                {
                    primes[ ++ cnt] = i;
                    while (n % i == 0)
                    {
                        n /= i;
                        num[cnt] ++ ;
                    }
                }
            if (n > 1) primes[ ++ cnt] = n, num[cnt] = 1;

     这个质因数分解相信大家都能够理解,y总模板套就完事了。

    接下来质因数分解好了之后 我们进行二分答案 

    首先,左区间我们设为1,右区间设为1e9(因为你的值最大就是这么多,其实也不必这么大)。

    我们从这个区间里找出一个mid,再对mid进行判断是否为满足条件的n,

    如果满足,那么我们就往左边继续找,同时记下此时的mid。

    至于为什么往左边?因为我们是找最小的n,如果此时的mid是满足的,但我们不知道它是否为最小的,所以我们要将查找的范围往左边移,即将r往左移。否则l 右移。

            int l = 1, r = 1e9;
            while (l < r)
            {
                int mid = (l + r) >> 1;
                if (check(mid)) r = mid;
                else l = mid + 1;
            }

    接下来就是check函数了 这里用到了一个我新学到的知识 ,求n!质因数因子的个数

    可以手写模拟一下,方法来自这里

    假如求10!中质因子2的个数,就是先对 t1=10/2=5,t2=t1/2=5/2=2, t3=t2/2=2/2=1,t4=0。所以总个数等于t1+t2+t3=8

    所以我们对应本题目中,求p的各个质因子primes[i]的个数num[i],是否全部满足各个质因子个数num[i]小于等于二分答案的这个值x!的各个质因子个数

    具体应用题目中就是

    bool check(int x)
    {
        for (int i = 1; i <= cnt; i ++ )
        {
            int t = x, sum = 0;
            while (t)
            {
                sum += t / primes[i];
                t /= primes[i];
            }
            if (sum < num[i]) return false;
        }
        return true;
    }

    综上 全部代码呈现

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <vector>
    #include <map>
    
    using namespace std;
    
    typedef long long LL;
    
    const int N = 10010;
    
    int primes[N], num[N], cnt;
    
    bool check(int x)
    {
        for (int i = 1; i <= cnt; i ++ )
        {
            int t = x, sum = 0;
            while (t)
            {
                sum += t / primes[i];
                t /= primes[i];
            }
            if (sum < num[i]) return false;
        }
        return true;
    }
    
    int main()
    {
        int t;
        cin >> t;
        while (t -- )
        {
            memset(num, 0, sizeof num);
            memset(primes, 0, sizeof primes);
            LL n;
            cin >> n;
            cnt = 0;
            for (int i = 2; i <= n / i; i ++ )
                if (n % i == 0)
                {
                    primes[ ++ cnt] = i;
                    while (n % i == 0)
                    {
                        n /= i;
                        num[cnt] ++ ;
                    }
                }
            if (n > 1) primes[ ++ cnt] = n, num[cnt] = 1;
            
            int l = 1, r = 1e9;
            while (l < r)
            {
                int mid = (l + r) >> 1;
                if (check(mid)) r = mid;
                else l = mid + 1;
            }
            cout << l << endl;
        }
        return 0;
    }
  • 相关阅读:
    2019 牛客多校第二场 H Second Large Rectangle
    2019 牛客多校题解目录
    2019 牛客多校第一场 F Random Point in Triangle
    2019 牛客多校第一场 E ABBA
    2019 牛客多校第一场 D Parity of Tuples
    2019 牛客多校第一场 C Euclidean Distance ?
    2019 牛客多校第一场 B Integration
    2019 牛客多校第一场 A Equivalent Prefixes
    Sigils of Elohim
    UVA 1599 Ideal Path
  • 原文地址:https://www.cnblogs.com/zbx2000/p/12799142.html
Copyright © 2011-2022 走看看