Title

【数论】两种特殊的质数筛法

数论——两种特殊的质数筛法(up2021729)

1. 埃氏筛

\[O(n log⁡log⁡n ) \]

  • 质数的倍数都是合数。借助这个性质,我们可以先找到一个质数,并利用这个质数,将范围内所有非质数(合数)的给先打上标记
  • 缺点:6会被2和3给打上两次标记,会造成计算的浪费
bool nprime[N];//0为否定,为质数 ,1为肯定,为非质数 
int prime[N],cntprime=0;
int main()
{
	int n;
	cin>>n;
	for(int i=2;i<=n;i++)
	{
	    if(!nprime[i])//质数为0,加上!来使得条件为true 
		{
            prime[cntprime++]=i;
			for(int j=2*i;j<=n;j=j+i)
	            nprime[j]=1;		
		}	
	}
}

2.欧拉筛

\[𝑂(𝑛) \]

  • 算法思想:限定每个数只会被其最小质因数筛到,而如果操作过程中出现比其大的数,那么直接退出了

  • 算法分析:

    m_prime数组用来记录这些数的最小质因数。

    质数的最小质因数为本身,而这个质数的倍数的最小质因数为这个质数。

    • m_prime[某个数]==初始化的值,这个数为质数。

    • m_prime[某个数]!=某个数本身时,这个数不是质数。

    (有点类似BFS)将存放质数的数组中各个质数乘上i(循环次数/当前轮次的放大倍数)

    • 循环结束条件:

      1. 当前质数*i>给定范围,质数如果再变大也必然会超过给定范围,所以是需要终止的。

      2. 当前质数大于m_prime[i]

      • prime[j]>m_prime[i], m_prime[i]是i的最小质因数,而这里是尝试将prime[j]*i(i的倍数)的最小质因数赋值成prime[j] (一个大于m_prime[i]的数),所以果断跳出。

欧拉筛模板

#include<bits/stdc++.h>
using namespace std;
const int  N = 数据筛查范围上界;
int main()
{
	int 每个数得最小质因子,质数数组,用来统计质数个数得变量;
	int n;
	cin>>n;
	for(int i=2;i<=n;i++)
	{
		if(!若当前这个数的最小质因子仍未被赋值)  则说明这个数是质数(不是其他质数的倍数)
		   将这个数的最小质因子记录一下,并将新的质数统计进来
		   
		接下来以这个数为基础去不断确认合数(通过这个数乘上一些比自己最小质因子还小的质数,来确定新生成的数是合数,并对他们的最大质因子作记录)
		for(int j=0;j<已有的质数个数;j++)
		{
            if(超过了已有的数据范围,就可以歇息一下了||当前遍历)
                break;
		    else 
		    	确认合数;
		}
	}
	cout<<cntprime;
	return 0;
}

代码

#include<bits/stdc++.h>
using namespace std;
const int  N = 1e6+10;
int main()
{
	int m_prime[N],prime[N],cntprime=0;
	int n;
	cin>>n;
	for(int i=2;i<=n;i++)
	{
		if(!m_prime[i])
		   m_prime[i]=prime[cntprime++]=i;
		for(int j=0;j<cntprime;j++)
		{
            if(prime[j]*i>n||prime[j]>m_prime[i])
                break;
		    else 
		    	  m_prime[i*prime[j]]=prime[j];
		}
	}
	cout<<cntprime;
	return 0;
}

题目集

AcWing 1292. 哥德巴赫猜想

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
int main()
{
	int m_prime[N],prime[N],cntprime=0;
    //O(n) 记录了每个数的最小质因子,和范围内所有的质数 
	int n;
	cin>>n;
	for(int i=2;i<=n;i++)
	{
		if(!m_prime[i])
		   m_prime[i] = prime[cntprime++] = i;
		for(int j=0;j>cntprime;j++)
		{
			if(prime[j]*i>n||prime[j]>m_prime[i])
	//到已经存好的质数里去找,一旦prime[j]大于i的最小质因子
	//就没有必要再将i的倍数的最小质数打上prime[j] 
			   break;
			else
			   m_prime[i*prime[j]]=prime[j];
		}
	}
	cout<<cntprime;
	return 0;
}
posted @ 2021-07-13 14:54  BeautifulWater  阅读(138)  评论(0编辑  收藏  举报