线性时间素数筛

求N以内的所有素数时,素数筛很常用,普通的素数筛原理是所有素数的倍数(2倍以上)为合数。代码类似于:

#include<vector>
#include<iostream>
using namespace std;
const int N=100;
vector<bool>isp(N,true);//isp[i]表示i是否为素数
void prime_sieve()
{
    for(int i=2;i<N;++i)
        if(isp[i])
            for(int t,k=2;(t=i*k)<N;++k)
                isp[t]=false;
}
int main()
{
    prime_sieve();
    for(int i=2;i<N;++i)
        if(isp[i])cout<<i<<endl;
}
在这种方法中很多数都会被多次标记导致浪费时间,很显然想到每个合数能不能只标记一次呢?能,哪一次呢?最小素因子乘以最大因子那次。有几个点:

1、一个合数可能有很多因子分解形式,其中有一个最大因子a乘以最小素因子b的分解,其中必有b<=a,这种分解就叫特殊分解吧,这种分解只有一次。

2、线性筛的思想就是,假设使用该方法筛出的所有合数,都是因为特殊分解才被标记的,

3、具体过程是,遍历N内的数,对于当前被遍历的数x,现有的任一素数p都是在x之前遍历时找到的所以不大于x

4、p*x就表示一个以p为最小素因子以x为最大因子的合数H,这里H就是普通素数筛中提到的素数的倍数,问题是怎么保证H没有被表示为其他的素数倍数。

新的素数筛就是解决了第四点,其实也很简单,p整除x时就不应该继续筛下去了。什么意思呢,对于x,假设现有的所有素数为{2,3,5……pa,pb,pc…},每次要做的就是把所有素数乘以x得到的数记为合数,现在假设pa<pb<=x且pa整除x,当标记到pa*x时就应该停下来,不妨假设x=pa*k,如果继续标记的话下一个是pb*x=pb*pa*k=pa*(pb*k)=U,如果此时标记U的话,那么U就不是被特殊分解标记的,U的特殊标记的最小素因子应是pa,而不是pb。

代码如下:

#include<vector>
#include<iostream>
using namespace std;
const int N=100;
vector<bool>isp(N,true);
void linear_prime_sieve()
{
    vector<int>prime;
    for(int i=2;i<N;++i)
    {
        if(isp[i])
            prime.push_back(i);
        for(int x:prime)
        {
            if(x*i>N)break;
            isp[x*i]=false;
            if(i%x==0)break;
        }
    }
}
int main()
{
    linear_prime_sieve();
    for(int i=2;i<N;++i)
        if(isp[i])cout<<i<<endl;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值