分解质因数

单个数分解质因数

算法原理
采用试除法分解质因数即可
时间复杂度
(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;
}
原文地址:https://www.cnblogs.com/G-H-Y/p/14520363.html