• 分解质因数


    单个数分解质因数

    算法原理
    采用试除法分解质因数即可
    时间复杂度
    (O(sqrt{n}))(O(frac{sqrt{n}}{ln(sqrt{n})}))

    阶乘分解质因数

    给定整数 (N),试把阶乘 (N!) 分解质因数,按照算术基本定理的形式输出分解结果中的 (p_i)(c_i) 即可。
    5
    2 3
    3 1
    5 1

    一般方法分析

    如果使用单个数分解质因数的方法,时间复杂度粗略估计为(O(n sqrt{n})),对于n的1e6的数据范围,大概率会超时

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 1e6 + 10;
    
    int primes_cnt[N];
    
    void divide(int n)
    {
        for (int i = 2; i <= n / i; ++ i)
        {
            if (n % i == 0)
            {
                int cnt = 0;
                while (n % i == 0)
                {
                    ++ cnt;
                    n /= i;
                }
                
                primes_cnt[i] += cnt;
            }
        }
        
        if (n > 1) ++ primes_cnt[n];
    }
    int main()
    {
        int n;
        cin >> n;
        
        for (int i = 2; i <= n; ++ i) divide(i);
        
        for (int i = 2; i <= n; ++ i) 
            if (primes_cnt[i] > 0) cout << i << ' ' << primes_cnt[i] << endl;
            
        return 0;
    }
    

    如果从优化的角度思考,如果能将divide中求cnt的过程进行预处理,快速求出n中质因子i的个数,复杂度会降低一些。
    但实际考虑到预处理(log_in)的时间复杂度为(O(n)),并且由于n的变化,每次都需要预处理,这样预处理就没有什么意义了。

    正解分析

    在一般方法中,我们的思考方向是对于每个数都进行一次分解质因数
    如果换种思考方向就是对于每一个质数,计算在阶乘中总共有多少个

    算法原理
    首先说明,上述的新的思考方向理论上是正确的,其可行性体现在以下的性质中

    • 性质1:(n!) 中 质因子 (p) 的个数为 (lfloor frac{n}{p} floor + lfloor frac{n}{p^2} floor + ... + lfloor frac{n}{p^k} floor).(该性质的证明位于 质因数分解计算组合数)
      使用该公式,对于每个质数而言,需要从(lfloor frac{n}{p} floor)(lfloor frac{n}{p^k} floor (p^k leq n , p^{k + 1} > n)),粗略计算为(log_pn)
      而1到a中的质数个数为(frac{n}{logn}),所以粗略计算该算法的时间复杂度为(O(n))

    流程

    1. 首先使用线性筛筛取可能范围内的质数
    2. 利用上述公式分别计算每个质数的个数

    代码实现

    #include <iostream>
    
    using namespace std;
    
    const int N = 1e6 + 10;
    
    int primes[N], cnt, st[N];
    
    void init(int n)
    {
        for (int i = 2; i <= n; ++ i)
        {
            if (!st[i]) primes[cnt ++] = i;
            for (int j = 0; primes[j] * i <= n; ++ j)
            {
                st[primes[j] * i] = true;
                if (i % primes[j] == 0) break;
            }
        }
    }
    int main()
    {
        int n;
        cin >> n;
        
        init(n);
        
        for (int i = 0; i < cnt; ++ i)
        {
            int p = primes[i], cnt = 0;
            for (int j = n; j; j /= p) cnt += j / p; // 使用while还需要定义临时变量,不如for简洁
            cout << p << ' ' << cnt << endl; // 不需要判断cnt是否为0,因为至少会是1,因为n!中一定包含小于n的质数,这些质数的质因子就是他们自身,所以所有的质数的指数最小也会是1
        }
        
        return 0;
    }
    
  • 相关阅读:
    为什么重写equals还要重写hashcode?
    谈谈关于Synchronized和lock
    springBoot为啥没有没有web.xml了
    springBoot整合mybatis开发
    springBoot的介绍与搭建
    Java i++原理及i=i++的问题说明
    Django学习笔记〇三——APP以及的文件结构
    Django学习笔记〇二——第一个Django项目
    Django学习笔记〇一——从web的概念引入
    MySQL学习笔记——〇六SQLAlchemy框架
  • 原文地址:https://www.cnblogs.com/G-H-Y/p/14520363.html
Copyright © 2020-2023  润新知