OJ刷题 |超大目标值(1亿)求质数个数问题

5 篇文章 1 订阅

欢迎关注微信公众号“Python小灶,和我一起每天学习Python新知识”
在这里插入图片描述

题目

质数也叫素数,求给定数值N以内的所有素数(只能被1和他本身整除的数),2是素数。

输入格式:
输入在一行中给出一个正整数N(1<N<100000000(1亿))。

输出格式:
输出质数总个数。

输入样例:
10

输出样例:
4

解题思路

1、暴力枚举,两重循环,外层循环控制从1到N的所有数,内层循环判断是不是质数(单独封装成函数),
判断质数很简单,找到一个除了1和他本身以外的因数就可以反证。因数的分布遵从 因数1 <= sqrt(n),
因数2 >= sqrt(n) ,随便想个数推算一下就行,很好理解。
当N较小时,可以用这个方法,但是当N较大时,将十分耗费时间到不可接受的地步。

代码

#include <stdio.h>
#include <math.h>

int isPrime(int n)
{
    int ret = 1;
    if (n == 2){
    	return ret;
    }
    for(int i=2; i<(sqrt(n) + 1); i++){
        if (n%i == 0){
            ret = 0; 
            break;
        }
    }
    return ret;
}


int main()
{
    int N = 0;
    int cnt = 1;
    scanf("%d", &N);
    
    for(int i=2; i<=N; i++){
        if (isPrime(i) == 1){
            cnt++;
        }
    }
    
	printf("%d\n", cnt);
    return 0;
}

2、埃拉托斯特尼筛法:
2是最小的质数,2的倍数都是合数(因为都能被2整除);
同理3的倍数也都是合数,以此类推。
所以我们给定一个布尔型数组,默认全零,然后从2开始,只要数组对应的值是0,我就判断它是不是质数,如果是,按照埃拉托斯特尼筛法把它的倍数全改为1,这样后面这个位置不需要再判断。
其中有个小技巧,我们可以写成(int j=ii; j<=N; j+=i) 而不是 (int j=2×i; j<=N; j+=i),这是因为例如5,只要标记55,56,57…为合数,因为52,53,5*4…已经被之前出现的数的倍数标记过了

代码

#include <stdio.h>
#include <math.h>

_Bool prime[100000000];
 
 // 函数描述
int isPrime(int n)
{
    int ret = 1;
    if (n == 2){
    	return ret;
    }
    for(int i=2; i<(sqrt(n) + 1); i++){
        if (n%i == 0){
            ret = 0; 
            break;
        }
    }
    return ret;
}


int main()
{
    int N = 0;
    int cnt = 0;
    scanf("%d", &N);
    for(int i=2; i<=N; i++){
        if (prime[i] == 0){
            if (isPrime(i) == 1){
                cnt++;
                for (int j=i*i; j<=N; j+=i){
                prime[j] = 1;
                }
            }
        }
    }
    printf("%d\n", cnt);
    return 0;
}

优化版

_Bool prime[100000000];
 
 // 函数描述
int main()
{
    int N = 0;
    int cnt = 0;
    scanf("%d", &N);

    for(int i=2; i<=N; i++){
        if (prime[i] == 0){
            cnt++;
            }
        for (int j=2; i*j<=N; j++){
            prime[i*j] = 1;
            
        }
    }
    printf("%d\n", cnt);
    return 0;
}

3、欧拉筛:
核心代码
for (int j=0; j<count&&p[j]i<=N; j++){
prime[p[j]i] = 1;
if(i%p[j] == 0){
break;
}
}
其中if(i%p[j] == 0) break;保证了每一个合数只被他的最小质因数筛选一次。
why?
该行保证了每一个合数只被它的最小质因数筛一次。
例如当i%prime[j]==0时,则i
prime[j+1]一定是prime[j]的整数倍,因为i可以整除prime[j],并且i
prime[j+1]/prime[j]>i所以在当前i中,iprime[j+1]还不能被筛,因为当前的i无法使得iprime[j+1]/prime[j]等于i*prime[j+1]的最小质因数。

代码

_Bool isPrime[100000000];
int prime[6000000] = {0};
 

  // 函数描述
int main()
{
    int N = 0;
    int cnt = 0;
    scanf("%d", &N);
    
    for(int i=2; i<=N; i++){ 
        // printf("%d,%d\n", i, isPrime[i]);
        if (isPrime[i]==0) prime[cnt++] = i;
            for (int j=0; j<cnt&&prime[j]*i<=N; j++){
                isPrime[prime[j]*i] = 1;
                if(i%prime[j] == 0) break;
                }
        }
    printf("%d\n", cnt);
    return 0;
}

优化版

_Bool isPrime[100000000];
int prime[6000000] = {0};

int main()
{
    int N = 0;
    int cnt = 1;
    scanf("%d", &N);
    
    for(int i=3; i<=N; i+=2){ 
        if (isPrime[i]==0) prime[cnt++] = i;
            for (int j=1; j<cnt&&prime[j]*i<=N; j++){
                isPrime[prime[j]*i] = 1;
                if(i%prime[j] == 0) break;
                }
        }
    printf("%d\n", cnt);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值