欧拉筛法/欧拉线性筛理解

先理解几个结论
①任何一个数n都可以表示成素数的乘积。对于素数来说显然成立;而合数可一分解为两个大于1的数m1和m2相乘,若m1、m2之中有合数,那么将其继续分解为两个大于1的数m1和m2相乘,重复这一步骤,最后一定可以将n分解成若干素数的乘积,这若干素数称为n的素因数。将n的全部素因数按升序排列为p1,p2,…,pk,则n=p1.p2…pk=p1.m(m=p2…pk),于是有
②任何一个合数都可以表示为其最小素因数与一个大于1的数相乘,反之必为素数。
③显然第一个最小素因数为p的合数是p的平方。
④设N以内所有素数按升序排列为p1,p2,…,pk,由①、②、③,N以内的所有合数,可按最小素因数将所有合数分为k类,第一类是最小素因数为p1的合数,第二类是最小素因数为p2的合数,依次类推。那么,N以内的所有合数为p1.(p1+0),p1.(p1+1),…,p1.(p1+a1),p2.(p2+0),p2.(p2+1),…,p2.(p2+a2),…,pk.(pk+0),pk.(pk+1),…,pk.(pk+ak)。其中pi.(pi+ai)<=N。

若n未被2至n-1的素数筛除,则必定为素数。

#include <iostream>
using namespace std;

const long long int N = 1e8;
 
long long cnt = 0,vis[N]={0},prim[N]={0};

 
void primeTable()//筛选出所有素数,存入prim数组
{
	for(long long i = 2; i<=N; i++)
	{
		if(!vis[i])//合数标记为1,任何一个合数n都可表示为小于n的素数p的k倍,即n = k*p, k<=n, p<=n;
		{
			prim[++cnt] = i;
		}
		
		for(long long j = 1; j<=cnt; j++)
		{
			long long t = i*prim[j];//筛选出最小素因数为prim[j]这一类的合数
			if(t>N)
				break;
			vis[t] = 1;//素数的倍数标记为合数
			if(!(i%prim[j]))
			{
				/******************************************
				若i整除prim[j],则 prim[j]是i的因数,
				且是最小素因数(prim[]中素数按升序排列),
				i*prim[j+1]...i*prim[j+a](j+a<=cnt)都是
				最小素因数为prim[j] 这一类的合数,因此无需重复标记。
				*******************************************/
				break;
			}
		}
	}
}
 
int main(){
    long long n;
    primeTable();

    while(cin>>n) 
    {
    	long long i = 1;
    	cout<<n<<"以内的所有素数:";
		while(prim[i]<=n)//打印n以内的所有素数
		{
	        cout<<prim[i++]<<" ";
	    }
	    cout<<endl<<"共计"<<i-1<<"个"<<endl;
	}
    return 0; 
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值