欧拉筛求解素数

求一个数是不是素数,我们最开始用到的方法是从2开始跑到这个数的前一项,如若这些数都不能被这个数整除,那么就称这个数是素数 。素数的概念是除了1和它本身之外不再有其他因数(除了1),我们称这样的数为素数。如果我们就按一般思路去实现求解这个数是不是素数,那么会用for循环从2开始跑到这个数的前一项,每个数都进行这样的操作,显然时间复杂度太高了,肯定会超时。这时我们就用一种快速的方法来判断一个数是不是素数。

我们用的方法是欧拉筛求解素数,其原理是我们假设每一个数都是素数,并都标记好初始值为零,用一个一维数组就行,这是我们就开始判断了,如果这个数是素数,即标记好的这个数值为零,然后就从这个数开始向后循环,只要是这个数的倍数,那这些数就都不是素数,并标记为1,这样下次循环就判断出这个数就不是素数了。当然如果都从当前这个素数开始向后跑标记后面的元素为1,那这样也跑了好多遍,我们的目的是用O(n)的复杂度计算出这个数是不是素数(当然先存在数组里复杂度就降到了O(1)),这时我们就得判断了,如果这个数判断过了就是非素数,那此时就不用再标记了,即当前这个数除以之前选出来的素数 若为零那就停止循环,进行下一次循环。

我们只需两个素组就能解决,代码如下

void olashai()
{
	memset(isprime,0,sizeof(isprime));
	for(ll i=2;i<maxn;i++)
	{
		if(isprime[i]==0)
			prime[tot++]=i;
		for(ll j=0;j<tot&&prime[j]*i<maxn;j++)
		{
			isprime[prime[j]*i]=1;
			if(i%prime[j]==0)
			break;
		}
	}
}

用这个方法需要两个数组,一个用来标记,一个用来存素数,这样我们可以再输入数据之前先把素数筛出来,后面用到就直接那这个数组用就行了,这样时间复杂度为O(1),当然如果题目还有什么其他的要求,我们可以在这个函数里面在添加上,例如给你一个数求这个数之前有多少个素数,这样我们可以再开一个数组用来记录某一数据之前有多少个素数。

代码见下

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
const int maxn=1e6+5;
typedef long long ll;
ll prime[maxn],isprime[maxn];
ll tot=0;
ll dis[maxn];
void olashai()
{
	memset(isprime,0,sizeof(isprime));
	for(ll i=2;i<maxn;i++)
	{
		if(isprime[i]==0)
		{
			prime[tot++]=i;
			dis[i]=dis[i-1]+1;
		}
		else
		dis[i]=dis[i-1];
		for(ll j=0;j<tot&&prime[j]*i<maxn;j++)
		{
			isprime[prime[j]*i]=1;
			if(i%prime[j]==0)
			break;
		}
	}
}
int main()
{
	olashai();
	int n;
	scanf("%d",&n);
	printf("%d\n",dis[n]); 
}

继续努力,天道酬勤!!!

猜你喜欢

转载自blog.csdn.net/qq_43916260/article/details/88086897