求1e8以为素数的个数【埃氏筛,线性筛(欧拉筛),埃氏筛升级版】

本文介绍了三种计算1亿以内素数个数的方法,包括传统的埃氏筛、快速的线性筛(欧拉筛)以及埃氏筛的升级版。在实践中,发现对于1e9以内的素数,使用map容器会导致无法得到结果,因此不适用。
摘要由CSDN通过智能技术生成
1e6      78498
1e7      664579
1e8      5761455 

埃氏筛(慢)

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e8;
int prime[MAXN+1],book[MAXN+1],cnt;
void getPrime()
{
	cnt=0;
	memset(book,0,sizeof(book));
	book[0]=book[1]=1;
	int i,j;
	for(i=2;i<=MAXN;i++)
	{
		if(!book[i])
		{
			prime[++cnt]=i;
			if(i>MAXN/i)	continue;
			for(j=i*i;j<=MAXN;j+=i)
				book[j]=1;
		}
	}
}
int main()
{
	getPrime();
	printf("%d\n",cnt);
	return 0;
}
为什么从 j = i * i 开始,不是 j = i * 2 
模拟出   j = i * 2 的表,会发现 i * (i-1) 之前标记过。

该算法无法避免的重复标记
比如:标记 3 * 49 和标记 7 * 21。

线性筛–欧拉筛(快)

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e8;
int prime[MAXN+1],book[MAXN+1],cnt; 
void getPrime()
{
	cnt=0;
	memset(book,0,sizeof(book));
	book[0]=book[1]=1;
	int i,j;
	for(i=2;i<=MAXN;i++)
	{
		if(!book[i])
			prime[++cnt]=i;
		for(j=1;j<=cnt&&i<=MAXN/prime[j];j++)
		{
			book[i*prime[j]]=1;
			if(i%prime[j]==0)	break;
		} 
	}
}
int main()
{
	getPrime();
	printf("%d\n",cnt);
	return 0;
}
理解该算法的关键:if(i%prime[j]==0)	break;
换句话理解:为什么不标记 i * prime[j+1] ?
拆分该表达式就可明白:
[ prime[j+1] * (i / prime[j]) ] * prime[j]
                              i * prime[j+1]
[ prime[j+1] * (i / prime[j]) ] > i ,同时 prime[j] < prime[j+1]
根据代码,现在不标记,后面一定会标记的。

埃氏筛法升级版(快)

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e8;
int prime[MAXN+1],book[MAXN+1],cnt;
void getPrime()
{
	cnt=0;
	memset(book,0,sizeof(book));
	book[0]=book[1]=1;
	int i,j;
	for(i=2;i<=(int)sqrt(MAXN);i++)//遍历sqrt(n)以内的素数
	{
		if(!book[i])
		{
			if(i>MAXN/i)	continue;
			for(j=i*i;j<=MAXN;j+=i)//标记合数
				book[j]=1;
		}
	}
	for(i=2;i<=MAXN;i++)
		if(!book[i])	prime[++cnt]=i;
}
int main()
{
	getPrime();
	printf("%d\n",cnt);
	return 0;
}
稍微解释一下原理:
合数可以由素数相乘而得
判断是是否为素数,只需判断sqrt(n)以内的因子即可.
因此只需判断sqrt(n)以内的素数即可. 

注意:
——1e9以内的素数个数用map容器标记跑不出来结果,放弃。

牛客例题1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值