欧拉筛法
用途
用于查找在一定范围内的所有素数
原理
在一定的范围内,如果一个数不为质数,那么它一定可以被表示为一个数和另一个质数的乘积,我们可以借此在一定范围内筛选掉不为质数的数,最后剩下的都为质数。
代码
#include<iostream>
using namespace std;
#define MAXN 100000010
#define ll long long
ll prime[MAXN];
bool vis[MAXN];
int cnt=0;
void Euler_prime(ll n)
{
for(ll i=2;i<=n;++i)
{
if(!vis[i])
{prime[cnt++]=i;vis[i]=true;}//vis[i]置为true或不置true都可以,储存我们的质数
for(ll j=0;j<cnt;++j)
{
if(i*prime[j]>n)//判断是否越界
break;
vis[i*prime[j]]=true;//筛数
}
}
}
ll N,Q;
int main()
{
scanf("%lld%lld",&N,&Q);
Euler_prime(N);
// 我们的范围为n
ll k;
for (int i = 1; i <= Q; i++)
{
scanf("%lld",&k);
printf("%lld\n",prime[k-1]);
// 查找第k个素数
}
}
进一步优化

可优化点
我们可以发现在这种模式下,我们对一些数进行了重复的操作,如30,在6 * 5,10 * 3, 15 * 2,中进行了三次判断,所以可以就此进行优化,这也是欧拉筛法的关键。
优化思路
我们可以发现6 * 5,10 * 3,15 * 3,其实都可以被三整除,那么我们可以加上如下判断
if(i*Prime[j]>n) break;
// 如果超出范围,那么结束循环
vis[i*Prime[j]] = true;
printf("%lld*Prime[%d] = %lld\n",i,j,i*Prime[j]);
if(i%Prime[j]==0) break;//时间复杂度为o(n)的关键。
一旦i能够被Prime[j]整除,那么i和后面比它大的数都可以被表示为Prime[j]*m(m为一个正整数),可以在后面进行(i*m)*Prime[j]时再进行消除。当然了,i还是要在这次进行处理的。
这样的话将只进行 15 * 2的操作,打表如下

完整欧拉筛法如下
void Euler_prime(ll n)
{
for(ll i=2;i<=n;++i)
{
if(!vis[i])
{prime[cnt++]=i;vis[i]=true;}//vis[i]置为true或不置true都可以,储存质数
for(ll j=0;j<cnt;++j)
{
if(i*prime[j]>n)//判断是否越界
break;
vis[i*prime[j]]=true;//筛数
if(!i%prime[j]) break;
}
}
}

本文详细介绍了欧拉筛法用于寻找一定范围内所有素数的原理和优化过程。通过避免对某些数的重复操作,实现了算法的时间复杂度优化,达到O(n)。并提供了完整的C++代码示例,展示了如何在实际编程中应用优化后的欧拉筛法。

338

被折叠的 条评论
为什么被折叠?



