素数筛:
原理:
- 数字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;
}