1. 程式人生 > >M - Help Hanzo LightOJ - 1197 (大區間求素數)

M - Help Hanzo LightOJ - 1197 (大區間求素數)

efi mil 為什麽 特殊 兩個 pre 大於 ons ++

題意:

求[a,b]之間的素數的個數

數很大。。。數組開不起

所以要想到轉化

因為小於等於b的合數的最小質因子 一定小於等於sqrt(b),所以只需要求出來[0,sqrt(b)]的素數 然後取倍數刪去[a,b]之間的合數 就好了

那 為什麽小於等於b的合數的最小質因子 一定小於等於sqrt(b)呢?

因為b是最大的, 所以只討論b即可 我們來看b的因子 。。一定是從 [0,sqrt(b)] 和 [sqrt(b),b]這兩個區間裏各取一個

先來看[0,sqrt(b)] 如果在這裏取得是一個合數 則這個合數可由比它小的質數組成 所以只討論質數即可 然後求倍數。。刪除[a,b]之間的合數

為什麽不看 [sqrt(b),b] 因為如果取一個這個區間的數去求倍數刪除[a,b]之間的合數的話 ,這個倍數一定是在 [0,sqrt(b)]這個區間的。。。

所以小於等於b的合數的最小質因子 一定小於等於sqrt(b)

代碼如下:

#include <iostream>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <map>
#include <set>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#include <cmath>
#define
MOD 2018 #define LL long long #define ULL unsigned long long #define maxn 100009 #define Pair pair<int, int> #define mem(a, b) memset(a, b, sizeof(a)) #define _ ios_base::sync_with_stdio(0),cin.tie(0) //freopen("1.txt", "r", stdin); using namespace std; const int LL_INF = 0x7fffffffffffffff,INF = 0x3f3f3f3f
; LL primes[maxn]; bool vis[maxn], bz[maxn]; int ans = 0; void init() { mem(vis,0); vis[1] = 1; for(int i=2; i<maxn; i++) if(!vis[i]) { primes[ans++] = i; for(LL j=(LL)i*i; j<maxn; j+=i) vis[j] = 1; } } int main() { init(); int T; int kase = 0; LL a, b; cin>> T; while(T--) { int res = 0; mem(bz,0); cin>> a >> b; // if(a <= 2) a = 2; int len = b - a; for(int i=0; i<ans && primes[i] * primes[i] < b; i++) { int j = a/primes[i]; if(j*primes[i] < a) j++; // 我們要找到第一個大於等於a的合數,因為出的時候是向下取整 所以要判斷一下 if(j <= 1) j++; // 如果j == 1 則說明 a是一個質數 但我們要找合數 { bz[j*primes[i] - a] = 1; j++; } } if(a == 1) bz[0] = 1; // a == 1時要特殊討論 因為1不是一個合數,無法由比它小的質數組成,也不是一個質數,所以在標記bz數組時 沒有標記 就會多算 for(int k=0; k<=len; k++) if(!bz[k]) res++; printf("Case %d: %d\n",++kase,res); } return 0; }

M - Help Hanzo LightOJ - 1197 (大區間求素數)