素数筛即埃氏筛法,找出小于等于给定数的所有素数个数。
大致思路就是空间换时间:首先建立数组将所有数设为true,从2开始,因为2为true,所以2为素数,然后将2的所有倍数设为false;再对3进行相同判定,以此类推。
1 int prime[Max_N]; //第i个素数 2 bool is_prime[MAX_N + 1]; //is_prime[i]为true表示i是素数 3 4 int sieve(int n){ 5 int p = 0; 6 for(int i=0;i<=n;i++) is_prime[i] = true; 7 for(int i=2;i<=n;i++) { 8 if(is_prime[i]) { 9 prime[p++] = i; 10 for(int j=2*i;j<=n;j+=i) is_prime[j] = false; 11 } 12 } 13 return p; 14 }
然后进阶的就是欧拉筛,即给定一个区间[a,b),找出区间内所有素数个数。
在前面的素数筛中,若循环中一个较大的素数x,开始筛他的倍数时,2x因为是2的倍数,所以已经在x=2时筛掉了;3x是3的倍数,也已经在x=3时筛掉了……。因此x需要筛掉的就只是x2之后的数。因此循环条件可以缩小至0~√b 即可。
这里我设置了两个数组,一个表示a~b之间的数,一个表示0~√b 之间的数。
1 typedef long long ll; 2 3 bool is_prime[MAX_L]; //is_prime[i-a] = true,则i是素数 4 bool is_prime_small[MAX_SORT_B]; 5 6 void segment_sieve(ll a,ll b) { 7 for(int i = 0; (ll)i*i < b; i++) is_prime_small[i] = true; 8 for(int i = 0; i < b - a; i++) is_prime[i] = true; 9 10 for(int i = 2; (ll)i*i < b; i++) { 11 if(is_prime_small[i]){ 12 for(int j = 2*i; (ll)j*j<b; j+=i) is_prime_small[j] = false; 13 for(ll j = max(2LL,(a + i - 1) / i) * i; j < b; j += i) is_prime[j - a] = false; 14 } 15 } 16 }