线性筛法

2016.1.25

 

学习完了伪线性的埃式筛法,我们来学习一个真线性的线性筛法。

时间复杂度:O(n)(即每个合数只会被筛一遍)

操作: 每当我们在外循环(外循环与埃式筛法相同)遇到一个素数时,我们将所有已筛得的素数(包括该素数)分别与该素数的乘积筛去;每当我们遇到一个合数时,则该合数可以表示为A=p1*p2*p3*……pk, pi<=pj (i<=j),那么我们筛去所有小于等于p1的素数分别与A的乘积。

代码如下:

int n,prime[1000005],e;
bool is_prime[1000005];//is_prime为0表示为素数 
void solve()//线性筛 
{
    prime[0]=prime[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!is_prime[i]) 
            prime[++e]=i;

                //无论i是否为素数都会执行到这一步,因为上述操作对于合数和素数是可以统一的
        for(int j=1;j<=e && i*prime[j]<=n;j++)
        {
            is_prime[i * prime[j]]=1;
            if(i % prime[j] == 0) break;//若i为素数,则这步不会执行;若i为合数,则prime[j]等于i中最小质因数时停止。
        }
    }
}
View Code

这个操作执行起来并不难,代码也容易看懂,关键是证明。

关于为什么当遇到合数A时只筛小于等于p1的素数与A的乘积:比如我们筛了一个比p1大的素数pn与A的乘积即pn*p1*p2*p3*……pk,那么当我们遇到pn*p2*p3*p4*……*pk时会再次筛掉pn*p1*p2*p3*……pk。

关于为何合数都会被筛除并且只筛一次:对于我们每遇到一个合数时,则该合数可以表示为A=p1*p2*p3*……pk, pi<=pj (i<=j),那么在这之前我们遇到的能筛掉A的B必须等于p2*p3*……pk, pi<=pj (i<=j),因为根据我们的操作,A/B必须不大于B中任意一个质因数,所以B有且只有一个,所以每个合数会且只会被筛一次。

证毕

原文地址:https://www.cnblogs.com/16er/p/5158938.html