质数相关知识

判断质数

对于一个数n,不借助后面质数数组的情况下,我们可以从2往后遍历来判断n是否有因子,从而判断其是否为质数。也就是从小到大找第一个质因子。时间复杂度O()。

cpp 复制代码
bool is_prime(int n)
{
    for(int i = 2; i <= n  / i; i ++)
        if(n % i == 0)return false;

    return true;
}

筛质数

目标:获得质数数组、O(1)判断一个数是不是质数

扩展:获得一个数的最小质因子

所需数组:

cpp 复制代码
int primes[N], cnt; // 质数数组
bool st[N]; // 判断质数
int p[N]; // 最小质因子(可选)

普通筛,用遍历到的数的倍数筛掉合数,时间复杂度O(nloglog n)

cpp 复制代码
void sieve(int n)
{
    for(int i = 2; i <= n; i ++)
    {
        if(!st[i])primes[cnt ++] = i;
        for(int j = i * 2; j <= n; j += i)
            st[j] = true;
    }
}

可以发现,在遍历的i时候明显重复给某些合数赋值了,比如12会在i=2,i=3,i=4,i=6的时候反复被筛掉。

埃式筛,用质数的倍数去筛掉合数,时间复杂度O(nloglog n)

cpp 复制代码
void sieve(int n)
{
    for(int i = 2; i <= n; i ++)
    {
        if(!st[i])
        {
            primes[cnt ++] = i;
            for(int j = i * 2; j <= n; j += i)
                st[j] = true;
        }
    }
}

在遍历的i时候还是会有某些质数重复给某些合数赋值,比如12会在i=2,i=3的时候反复被筛掉。

线性筛,用最小的质因子去筛掉对应合数,时间复杂度O(n)

cpp 复制代码
void sieve(int n)
{
    for(int i = 2; i <= n; i ++)
    {
        if(!st[i])primes[cnt ++] = i;
        for(int j = 0; primes[j] <= n / i; j ++)
        {
            st[primes[j] * i] = true;
            if(i % primes[j] == 0)break;
        }
    }
}

可以分析一下为什么是这样的:

因为j从小到大遍历,即质数从小到大遍历,所以primesj一定小于等于i的最小质因子,因为

if(i % primesj != 0),那么说明i的最小质因子还没有被遍历到,

if(i % primesj == 0),这时候说明i的最小质因子就是primesj,直接break,

这样就可以保证primesj * i的最小质因子就是primesj

所以我们就一直在用最小质因子去筛合数,每个合数只会被遍历一次。

存下这个最小质因子就很简单了

cpp 复制代码
void sieve(int n)
{
    for(int i = 2; i <= n; i ++)
    {
        if(!st[i])primes[cnt ++] = i, p[i] = i;
        for(int j = 0; primes[j] <= n / i; j ++)
        {
            st[primes[j] * i] = true;
            p[primes[j] * i]  = primes[j];
            if(i % primes[j] == 0)break;
        }
    }
}

分解质因数

一个大于1的数可以被分解为若干个质数的乘积

从小到大找即可,下面输出质因子及个数

cpp 复制代码
void work(int x)
{
    for(int i = 2; i <= x / i; i ++)
    {
        int cnt = 0;
        if(x % i == 0)
        {
            while(x % i == 0)
            {
                x /= i; 
                cnt ++;
            }
            cout<<i<<' '<<cnt<<endl;
        }
    }
    if(x > 1)cout<<x<<' '<<1<<endl;
}
相关推荐
Beyond_System|系统之外19 分钟前
【学编程】Python基础编程题100道(21-60)
开发语言·python·算法
漂流瓶jz2 小时前
UVA-1442 洞穴 题解答案代码 算法竞赛入门经典第二版
c++·算法·题解·aoapc·算法竞赛入门经典·uva
叠层归一研究院3 小时前
基于极限自指的叠层归一宇宙结构理论——无元外部封闭系统的内生区分模型
人工智能·经验分享·算法·agi
Selvaggia4 小时前
Diffusion Model 的基本原理与模型架构
算法
wabs6666 小时前
关于二叉树【力扣572.另一棵树的子树的思考】
数据结构·c++·算法·leetcode·二叉树
hanlin036 小时前
刷题笔记:力扣第41题-缺失的第一个正数
笔记·算法·leetcode
shehuiyuelaiyuehao6 小时前
算法50,分治归并,数组中的逆序对
java·算法
阳明山水7 小时前
校准分位数驱动智能库存决策
人工智能·深度学习·算法·机器学习·架构
别动我齐刘海8 小时前
ROS2 Jazzy + C++ 实战路线——进阶学习3
c++·人工智能·vscode·python·算法·机器学习·机器人
zhangfeng11338 小时前
《从“人工适配“到“智能生成“:KernelSwift 跨国产芯片算子迁移全栈方案解读》 —— 强调范式跃迁和跨硬件属性,适合偏架构分析的写法
人工智能·算法·华为·ai编程·npu