線性篩質數
阿新 • • 發佈:2020-09-03
暴力
講解
對於每個數,我們用\(O(\sqrt n)\)的時間判斷是否是質數
所以時間複雜度是\(O(n\sqrt n)\)
程式碼就不給出了
埃式篩法
講解
一個很簡單的篩法
對於每個質數,將它所有的倍數打上標記,表示不是質數
然後就可以做到\(O(nlogn)\)篩質數了
程式碼
bool vis[MAXN]; int prime[MAXN],pn; void sieve(int x) { for(int i = 2;i <= x;++ i) { if(!vis[i]) { prime[++pn] = i; for(int j = i*2;j <= x;j += i) vis[j] = 1; } } }
歐式篩法
講解
由於埃式篩法每個合數會被所有的質因數篩一遍,所以時間複雜度是\(O(nlogn)\)的
但是歐式篩法保證每個合數只會被最小的質因數篩一遍,從而保證了\(O(n)\)的時間複雜度
它是這麼實現的(配程式碼食用更佳):
首先外層迴圈從\(2\)開始列舉倍數\(i\),如果發現當前數字不是質數,加入質數的集合
內層迴圈列舉已經篩出來的質數\(p_j\),將\(i*p_j\)打上標記,如果\(i\)是\(p_j\)的倍數,直接跳出迴圈
為什麼可以直接跳出迴圈呢?
令\(j'>j\),所以\(p_{j'}>p_j\),因為\(i\)是\(p_j\)的倍數,所以\(i*p_{j'}\)
我們希望每個合數被最小的質因數篩掉,而\(p_j<p_{j'}\),所以可以直接跳出迴圈
程式碼
bool vis[MAXN]; int prime[MAXN],pn; void sieve(int x) { for(int i = 2;i <= x;++ i) { if(!vis[i]) prime[++pn] = i; for(int j = 1;j <= pn && i * prime[j] <= x;++ j) { vis[i * prime[j]] = 1; if(i % prime[j] == 0)//超強優化! break; } } }