质数(例题+代码)

本文介绍了质数的定义,并提供了两种质数判定算法:朴素版和优化版,时间复杂度分别为O(n)和O(sqrt(n))。接着讨论了如何使用筛法进行质因数分解,包括普通筛法、埃氏筛和线性筛,分析了它们的时间复杂度。最后给出了相关例题和解题代码,涉及质数判定和质因数分解问题。
摘要由CSDN通过智能技术生成

质数

1.质数的定义

质数(Prime number),又称素数,指在大于 1 1 1 的自然数中,除了 1 1 1 和该数自身外,无法被其他自然数整除的数(也可定义为只有 1 1 1 与该数本身两个正因数的数)。大于 1 1 1 的自然数若不是质数,则称之为合数(也称为合成数)

2.相关例题

2.1 质数的判定

1. 朴素版

我们可以从质数的定义出发,质数是大于 1 1 1 的并且只能被1和本身整除的数。换而言之,质数就不能被 2   ∼ n − 1 2~\sim n-1 2 n1之间的数整除(假定该数为 n n n ),我们就可以由此来判断。

时间复杂度: O ( n ) O(n) O(n)

C++代码:

bool is_prime(int x){
    if(x < 2) return false;
    for(int i = 2;i <= n;i++){
        if(x % i == 0) return false;
    }
    return true;
}
2. 优化版

我们注意到如果一个数 a a a 能够整除 n n n,那么 n / a n/a n/a(也就是另外一个因子)也能够整除 n n n 。例: 2 2 2 能够整除 8 8 8 ,那么 8 / 2 = 4 8 / 2 = 4 8/2=4 也能够整除 8 8 8。所以我们实际上只需要枚举到 O ( s q r t ( n ) ) O(sqrt(n)) O(sqrt(n)) 就能判断一个数到底是不是质数。

时间复杂度: O ( n ) O(\sqrt{n}) O(n )

C++代码:

bool is_prime(int x){
    if(x < 2) return false;
    //这里不用 i * i <= x 是因为 当x这个数比较大的时候,i * i 有溢出的风险
    for(int i = 2;i <= x/i;i++){
        if(x % i == 0) return false;
    }
    return true;
}

3. 例题
题目链接

试除法判定质数

题目描述

给定 n n n 个正整数 a i a_i ai,判定每个数是否是质数。

输入格式

第一行包含整数 n n n

接下来 n n n 行,每行包含一个正整数 a i a_i ai

输出格式

n n n 行,其中第 i i i 行输出第 i i i 个正整数 a i a_i ai 是否为质数,是则输出 Yes,否则输出 No

数据范围

  • 1 ≤ n ≤ 100 1≤n≤100 1n100
  • 1 ≤ a i ≤ 2 31 − 1 1≤ai≤2^{31}−1 1ai2311

输入样例:

2
2
6

输出样例:

Yes
No

C++代码:

#include<bits/stdc++.h>
using namespace std;

bool is_prime(int x){
    if(x < 2) return false;
    for(int i = 2;i <= x/i;i++){
        if(x % i == 0) return false;
    }
    return true;
}

int main(){
    int n;
    cin>>n;
    for(int i = 1;i <= n;i++){
        int x;
        cin>>x;
        if(is_prime(x)) puts("Yes");
        else puts("No");
    }
    return 0;
}

2.2 分解质因数

1.基本思想:

唯一分解定理:一个数 n n n 肯定能被分解成 n = p 1 a 1 × p 2 a 2 × p 3 a 3 × . . . p n a n n=p_1^{a_1} \times p_2^{a_2} \times p_3^{a_3} \times... p_n^{a_n} n=p1a1×p2a2×p3a3×...pnan p p p是素因子, a a a是素因子的个数)​ 因为一个数肯定是由合数和质数构成的,而合数又能被质数分解。例如: 20 = 2 × 2 × 5 20 = 2 \times 2 \times 5 20=2×2×5 16 = 2 × 2 × 2 × 2 16 = 2 \times 2 \times 2 \times 2 16=2×2×2×2
此外,一个数只可能存在一个 ≥ s q r t ( n ) \geq sqrt(n) sqrt(n)的质因子。例如: 20 = 2 × 2 × 5 20 = 2 \times 2 \times 5 20=2×2×5 5 5 5 就是这个 ≥ 20 \geq \sqrt{20} 20 的质因子。

2. 代码

时间复杂度: O ( n ) O(\sqrt{n}) O(n )

C++代码:

//该函数 会打印出x的所有质因子 已经对应的个数
void divide(int x){
    //这里保证了 每次能整除x 的 i都是质数
    for(int i = 2;i <= x/i;i++){
        //用cnt记录本轮可能会存在的质因子个数
        int cnt = 0;
        //如果i 能整除 x,那么就通过这个while循环将x中的所有除掉,并记录个数
        if(x % i == 0){
            while(x % i == 0){
                x /= i;
                cnt++;
            }
            printf("%d %d\n",i,cnt);
        }
    }
    //如果循环结束 x的值还>1 说明x就是剩下的唯一那个 大于 sqrt(x) 的质因子
    if(x > 1) printf("%d %d\n",x,1);
}
3.例题:
题目链接

分解质因数

题目描述

给定 n n n 个正整数 a i a_i ai,将每个数分解质因数,并按照质因数从小到大的顺序输出每个质因数的底数和指数。

输入格式

第一行包含整数 n n n

接下来 n n n 行,每行包含一个正整数 a i a_i ai

输出格式

对于每个正整数 a i a_i ai,按照从小到大的顺序输出其分解质因数后,每个质因数的底数和指数,每个底数和指数占一行。

每个正整数的质因数全部输出完毕后,输出一个空行。

数据范围

  • 1 ≤ n ≤ 100 1≤n≤100 1n100
  • 2 ≤ a i ≤ 2 × 1 0 9 2≤a_i≤2×10^9 2ai2×109

输入样例:

2
6
8 

输出样例:

2 1
3 1

2 3

时间复杂度: O ( n ) O(\sqrt{n}) O(n )

C++代码:

#include<bits/stdc++.h>
using namespace std;

void divide(int x){
    for(int i = 2;i <= x/i;i++){
        int cnt = 0;
        if(x % i == 0){
            while(x % i == 0){
                x /= i;
                cnt++;
            }
            printf("%d %d\n",i,cnt);
        }
    }
    if(x > 1) printf("%d %d\n",x,1);
}

int main(){
    int n;
    scanf("%d",&n);
    while(n--){
        int x;
        cin>>x;
        divide(x);
        puts("");
    }
    return 0;
}

2.3筛质数

1.最普通的筛法

我们从 2 2 2 开始遍历,如果当前数没有被筛去,就是质数,每次循环都将小于 总数 x x x i i i 的倍数筛去。
例如:当 x = 8 x = 8 x=8,从 2 2 2 开始遍历
i = 2 i = 2 i=2 i i i 没有被筛去,是质数,所以记录下来。筛去 4 , 6 , 8 , 12 , 14 , 16 , 20 , . . . 4,6,8,12,14,16,20,... 4,6,8,12,14,16,20,...
i = 3 i = 3 i=3 i i i 没有被筛去,是质数,所以记录下来。筛去 6 , 9 , 12 , 15 , 18 , 21 , 24 , . . . 6,9,12,15,18,21,24,... 6,9,12,15,18,21,24,...

循环结束以后,所有的质数都已经被标记了

时间复杂度: O ( n × l o g n ) O(n \times logn) O(n×logn)

C++代码:

void get_prime(){
    for(int i=2;i<=n;i++){
        //prime数组记录质数,cnt记录质数的个数
        if(!st[i]) primes[cnt++]=i;
        
        //筛去i的倍数,就是将st[j] 置为 true
        for(int j=i;j<=n;j+=i){
            st[j]=true;
        }
    }
}
2.优化版:埃氏筛

实际上我们会发现普通的筛法做了太多重复的工作:
i = 2,筛去4,68,10,12,14…
i = 3,筛去6,9,12,15…
i = 4,筛去812,16…

由之前的唯一分解定理可知,一个数是肯定可以分解为若干个质数的乘积的,所以我们实际上只需要筛去每个质数的倍数就好了

时间复杂度: O ( n × l o g l o g n ) O(n \times loglogn) O(n×loglogn)

C++代码:

void get_primes(){
    for(int i=2;i<=n;i++){
        //当st[i] = false时,说明此时的i是质数
        if(!st[i]){
            //记录质数
            primes[cnt++]=i;
            //筛去质数的倍数
            for(int j=i;j<=n;j+=i) st[j]=true;
        }
    }
}
3.最终版:线性筛

通过观察我们会发现,虽然埃氏筛法相比于普通的筛法,已经减少了很多重复性的操作。但是还是存在一些重复的操作。
例如: 30 = 2 × 3 × 5 30 = 2 \times 3 \times 5 30=2×3×5
i = 2 i = 2 i=2 时,会把 30 30 30 筛一次
i = 3 i = 3 i=3 时,也会把 30 30 30 筛一次
i = 5 i = 5 i=5 时,也会把 30 30 30 筛一次

实际上我们可以考虑,每次都用一个数的最小质因子来把它筛掉,后面的就直接忽略。比如 30 30 30,我们只需要 i = 2 i = 2 i=2 的时候将它筛掉, i = 3 i = 3 i=3 i = 5 i = 5 i=5 的时候都不对它进行操作。

时间复杂度: O ( n ) O(n) O(n)

C++代码:

void get_prime(){
    
    for(int i=2;i<=n;i++){
        //记录质数
        if(!st[i]) primes[cnt++]=i;
        //筛去小于等于n 的质数的倍数
        for(int j=0;primes[j]<=n/i;j++){
            st[primes[j]*i]=true;
            //因为我们是从小到大枚举的,所以primes数组的中的质数也是 2,3,5,7....
            //所以当我们第一次遇到 i % primes[j]==0时,说明此时的
            //primes[j]就是i的最小质因子,上面的那句st[primes[j]*i]=true
            //已经通过这个最小质因子筛去了对应的合数
            //所以我们就忽略后面的操作 直接退出循环就好
            if(i%primes[j]==0) break;
        }
    }

}
4.例题
题目链接

筛质数

题目描述

给定一个正整数 n n n,请你求出 1 ∼ n 1\sim n 1n质数的个数

输入格式

共一行,包含整数 n n n

输出格式

共一行,包含一个整数,表示 1 ∼ n 1 \sim n 1n 中质数的个数。

数据范围

  • 1 ≤ n ≤ 1 0 6 1≤n≤10^6 1n106

输入样例:

8

输出样例:

4

时间复杂度: O ( n ) O(n) O(n)

C++代码:

#include<bits/stdc++.h>
using namespace std;

const int N = 1e6+10;
int st[N],prime[N];

int main(){
    int n;
    cin>>n;
    int cnt = 0;
    for(int i = 2;i <= n;i++){
        if(!st[i]) prime[cnt++] = i;
        for(int j = 0;prime[j] <= n/i;j++){
            st[prime[j] * i] = 1;
            if(i % prime[j]==0) break;
        }
    }
    printf("%d\n",cnt);
    return 0;
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值