[模板]——素数筛、大区间素数筛

素数筛:

原理:

  1.     数字2是素数。
  2.     在数字K前,每找到一个素数,都会删除它的倍数,即以它为因子的整数。如果k未被删除,就表示2->k-1都不是k的因子,那k自然就是素数了。

优化:

    乘子不需要从1遍历到maxn,只需要遍历素数队列即可。这里主要展示模板,具体证明百度一下吧(好吧我实在不想证了)

int Mark[maxna]={0};//0表示素数 
int prime[maxna];
int Prime()
{
	int index=0;
	int i,j;
	//   memset(Mark,0,sizeof(Mark));
	for( i = 2; i<maxn; i++)
	{
		if(Mark[i] == 0)
			prime[index++]=i;
		for(int j=0;j<index && prime[j]*i<maxn;j++)
		{
			Mark[i*prime[j]]=1;
			if(i % prime[j] == 0)
				break;
		}
	}
	Mark[1]=1;
	return index;
}

大区间素数筛:

【分析】b以内的合数的最小质因数一定不超过sqrt(b)。如果有sqrt(b)以内的素数表的话,就可以把埃式筛法运用在[a,b)上了。也就是说,先分别做好[2,sqrt(b))的表和[a,b)的表,然后从[2,sqrt(b))的表中筛得素数的同时,也将其倍数从[a,b)的表中划去,最后剩下的就是区间[a,b)内的素数了。 

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define MAX_L 1000007

bool is_prime[MAX_L];
bool is_prime_small[MAX_L];
//对区间[a,b)内的整数执行筛法。isprime[i - a]=true <=> i是素数
void segment_sieve(LL a,LL b)

{

    for(int i=0; (LL)i*i < b; i++)

        is_prime_small[i]=true;

    for(int i=0; i<b-a; i++)

        is_prime[i]=true;

    for(int i=2; (LL)i * i<b; i++)

        if(is_prime_small[i])

        {

            for(int j=2*i; (LL)j * j < b; j += i)

                is_prime_small[j]=false;//筛[2,sqrt(b))

            for(LL j=max(2LL, (a+i-1)/i)*i ; j<b; j+=i) //(a+i-1)/i为[a,b)区间内的第一个数至少为i的多少倍.

                is_prime[j - a] =false;//筛[a,b)

        }

}

int main()

{

    long long a,b,t;

    while(~scanf("%lld %lld",&a,&b))

    {

        segment_sieve(a,b);

        while(cin>>t)

        {

        	if(t<a || t>=b)

        	cout<<"error\n";

        	if(a==1 && t==1)

cout<<0<<endl; //要特例判断 a=1

        	else cout<<is_prime[t-a]<<endl;

        }

    }

    return 0;

}


猜你喜欢

转载自blog.csdn.net/greybtfly/article/details/80672397
今日推荐