筛素数

目录

一、一般筛素数(埃拉托斯特尼筛法)

二、线性筛素数(欧拉筛法)


 

一、一般筛素数(埃拉托斯特尼筛法)

此筛选法的时间复杂度是O(nloglogn)

int vis[maxn];
memset(vis,1,sizeof(vis));
void isprime()
{
	int prime[maxn],cnt=0;
    for(int i=2;i<=sqrt(N);i++)
    {
        if(vis[i])
        {
        	prime[cnt++]=i;
            for(int j=i*i;j<=N;j+=i)
                vis[j]=0;//i是素数,则下一个起点是i*i,把后面的所有的i*i+2*n*i筛掉
        }
    }
}
 

这种方法比较好理解,初始时,假设全部都是素数,当找到一个素数时,显然这个素数乘上另外一个数之后都是合数(注意上面的 i*i ,  比 i*2 要快点 ),把这些合数都筛掉。

但仔细分析能发现,这种方法会造成重复筛除合数,影响效率。比如10,在i=2的时候,k=2*15筛了一次;在i=5,k=5*6 的时候又筛了一次。所以,也就有了快速线性筛法。

 

二、线性筛素数(欧拉筛法)

线性筛,复杂度为O(n)。与埃氏筛相比,不会对已经被标记过的合数再进行重复标记,故效率更高。欧拉筛将合数分解为 (最小质因数 * 一个合数) 的形式,通过最小质因数来判断当前合数是否已经被标记过。

int vis[maxn];
memset(vis,0,sizeof(vis));
void isprime()
{
	int prime[maxn],cnt=0;//cnt用来计数,prime数组保存素数 
	for(int i=2;i<=n;i++)
	{
		if(!vis[i])prime[cnt++]=i;//如果未被标记过,则表示为素数 
		for(int j=0;j<cnt && i*prime[j]<=n;j++)//当标记的合数超出范围则退出 
		{
			vis[i*prime[j]]=1;
			if(i%prime[j]==0)break;//关键步骤 
		}
	}
}

难点就在于对if (i % prime[j] == 0)这步的理解,意思是每个数保证被它的最小质因数筛出,即当i是prime[j]的整数倍时,记 m = i / prime[j],那么 i * prime[j+1] 就可以变为 (m * prime[j+1]) * prime[j],这说明 i * prime[j+1] 是 prime[j] 的整数倍,不需要再进行标记(在之后会被 prime[j] * 某个数 标记),对于 prime[j+2] 及之后的素数同理,直接跳出循环,这样就避免了重复标记。

 

欧拉筛素数的其他应用:因为prime[j]必定是prime[j]*i的最小质因子。所以这个性质在某些题里可以用到。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值