分解质因数

单个数分解质因数

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

阶乘分解质因数

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

一般方法分析

如果使用单个数分解质因数的方法,时间复杂度粗略估计为O(nn),对于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的个数,复杂度会降低一些。
但实际考虑到预处理login的时间复杂度为O(n),并且由于n的变化,每次都需要预处理,这样预处理就没有什么意义了。

正解分析

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

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

  • 性质1:n! 中 质因子 p 的个数为 np + np2 + ... + npk.(该性质的证明位于 质因数分解计算组合数)
    使用该公式,对于每个质数而言,需要从npnpk(pkn,pk+1>n),粗略计算为logpn
    而1到a中的质数个数为nlogn,所以粗略计算该算法的时间复杂度为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;
}
posted @   0x7F  阅读(574)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示