阶乘 -> 求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;
}

 

posted @ 2020-04-29 15:44  haust_zbx  阅读(670)  评论(0编辑  收藏  举报