有兩種作法,一種是打表,另外一種是直接求。ios
將1e11每隔len(len=2000w)個數字統計一下該區間內素數的個數,好比cnt[1] 表示[1,len]之內有多少個素數,cnt[2]表示[len+1,2*len】之內有多少個素數,依次類推。數組
而後維護一下前綴和,sum[i] = cnt[1] + ....+ cnt[i]spa
那麼給定一個數字n,求[1,n]之內有多少個素數, 那麼只要統計一下sum[n/len],而後再統計一下區間[n/len*len+1, n/len*len + n%len],因爲這個內最多隻有2000w個,那麼只要對該區間內的數字進行篩法求素數,而後統計該區間內素數的個數就能夠了。code
因此關鍵是若是求任意區間內素數的個數, 例如要求區間[a, b]內有多少個數字, 由於該區間內任意合數字的最大最小質因數不會超過sqrt(b),因此只要先求出區間[2,sqrt(b)]內的素數表,那麼就能夠用該素數表去篩去區間[a,b]內的全部合數。blog
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <math.h> #include <stdlib.h> #include <time.h> using namespace std; typedef long long LL; /* * 要求區間[a,b]之內的素數, 那麼該區間內全部合數的最小質因數絕對不超過sqrt(b), * 因此只要求出[2,sqrt(b)]之內的全部素數,而後用這些素數篩去區間[a,b]內的全部合數便可 * 要開的數組的大小 * M > b - a * N > sqrt(b) */ const int N = 1000000; const int M = 10000000; bool is_prime[N]; int prime[N], cnt; void get_prime(){ for(int i=3; i<N; ++i) is_prime[i] = true; cnt = 0; prime[cnt++] = 2; for(LL i=3; i<N; i+=2){ if(is_prime[i]){ prime[cnt++] = i; for(LL j=i*i; j<N; j+=2*i){ is_prime[j] = false; } } } } bool is_prime2[M]; int get_prime2(LL l, LL r){ for(LL i=0; i<=r-l; ++i) is_prime2[i] = true; for(LL i=0; i<cnt && (LL)prime[i]*prime[i]<=r; ++i){ /* (l+prime[i]-1)/prime[i]*prime[i] 獲得最接近l的prime[i]的倍數是多少 */ for(LL j=max(2LL, (l+prime[i]-1)/prime[i])*prime[i]; j<=r; j+=prime[i]){ is_prime2[j-l] = false; } } int res = 0; //會把0和1當作素數,因此要減去 if(l==0) res -= 2; if(l==1) res -= 1; for(LL i=0; i<=r-l; ++i){ res += is_prime2[i]; /* printf("%lld %d\n", i+l, is_prime2[i]); */ } return res; } int main() { /* freopen("in.txt","r",stdin); */ /* freopen("out.txt","w",stdout); */ get_prime(); cout << get_prime2(1, 10000000) << endl; return 0; }