今年CCPC网络赛只做出了4个题,想做的第5个题是有关素数筛的问题 原题是1e10的数据,当时没有想到解决办法,所以最近补一下有关素数筛的问题
普通筛法:
复杂度:O(n√n)
介绍:这个算法是最简单的素数判断算法+遍历素组,耗时长
#include <bits/stdc++.h>
using namespace std;
int factor[1000010];
int prime[1000010];
int get_prime(int n)
{
int i,j,p=0,flag;
for(i=2; i<=n; i++)
{
flag=1;
for(j=2; j<=sqrt(i); j++)
if(i%j==0)
{
flag=0;
break;
}
if(flag==1)
prime[p++]=i;
}
return p;
}
int main()
{
int n,i;
scanf("%d",&n);
int flag=get_prime(n);
for(i=0; i<flag; i++)
printf("%d ",prime[i]);
return 0;
}
埃式筛:
复杂度:O(nloglogn)
介绍:埃拉托斯特尼筛法,利用当前已经找到的素数,从后面的数中筛去当前素数的倍数,由预备知识一可知,当前素数已经是筛去数的质因子,如此下去能筛除所有之后的合数,是一种比较快的筛法
#include <bits/stdc++.h>
using namespace std;
bool is_prime[1000010];
int prime[1000010];
int get_prime(int n)
{
int i,j,p=0,flag;
memset(is_prime,true,sizeof(is_prime));
is_prime[0]=is_prime[1]=false;
for(i=2; i<=n; i++)
{
if(is_prime[i])
{
prime[p++]=i;
for(j=i*2; j<=n; j+=i)
is_prime[j]=false;
}
}
return p;
}
int main()
{
int n,i;
scanf("%d",&n);
int flag=get_prime(n);
for(i=0; i<flag; i++)
printf("%d ",prime[i]);
return 0;
}
欧拉晒:
复杂度:O(N)
介绍:这是一种很好的线性筛法,和埃氏筛法的区别是对于每一个要筛除的数,欧拉筛法只筛除一次,而埃氏筛法会重复筛除,比如8和16同时被2和4筛去,推荐使用欧拉筛法
#include <bits/stdc++.h>
using namespace std;
int factor[1000010];//记录最小素因子
int prime[1000010];//记录素数
int get_prime(int n)
{
int i,j,p=0;
for(i=2; i<=n; i++)
{
if(factor[i]==0)
{
prime[p++]=i;
factor[i]=i;
}
for(j=0; j<p&&prime[j]*i<=n; j++)
{
factor[prime[j]*i]=prime[j];
if(i%prime[j]==0)
break;
}
}
return p;
}
int main()
{
int n,i;
scanf("%d",&n);
int flag=get_prime(n);
for(i=0; i<flag; i++)
printf("%d ",prime[i]);
return 0;
}
区间筛法:(暂时还不会)
介绍:对于于超大区间,如a<b<=10^12 ,b-a<=10^6,这种情况下,数组是开不到这么大的,所以要用偏移来筛选,具体是先打一个2-√b的小表,然后用此表来筛除a到b的素数
#include <bits/stdc++.h>
using namespace std;
bool is_prime[1000010];
bool prime[1000010];
long long int sum=0;
void get_prime(long long int a,long long int b)
{
long long int i,j,p=0,flag;
for(i=0; i*i<b; i++)
prime[i]=true;
for(i=0; i<b-a; i++)
is_prime[i]=true;
for(i=2; i*i<b; i++)
{
if(prime[i])
{
for(j=2*i; j*j<b; j+=i)
prime[j]=false;
for(j=max((long long)2,(a+i-1)/i)*i; j<b; j+=i)
is_prime[j-a]=false;
}
}
}
int main()
{
long long int a,b,i;
scanf("%lld%lld",&a,&b);
get_prime(a,b);
for(i=0; i<b-a; i++)
if(is_prime[i])
sum++;
printf("%lld\n",sum);
return 0;
}