關於線性素數篩

2021-08-26 21:00:59 字數 903 閱讀 2932

去年聽數一聚聚講的線性篩,但是之前只記了板子,也沒有對其進行過深入思考。

模板:bool notprime[n];

int cnt,prime[n];

void init(){

notprime[1]=1;

for(int i=2;i最近發現很多人對線性篩的break有疑問——雖然此前我自己也一知半解,只記得數一聚聚強調過,加上這個才使得這個篩法是線性的——然後就略微琢磨了一下break的妙處。

當然更具體的原因是我用線性篩寫的  這道題的題解下面有童鞋提問了,因此思索了一會兒才給出了解釋。

「首先可以知道每個合數都無法避免被它最小的素因子篩一次——因為是從小到大列舉的素數,而break是為了保證每個數隻被篩一次,比如i=4,prime[j]=2時如果不break,x=i*prime[j+1到cnt-1]都會在這裡被篩一次,但是因為i是prime[j]的倍數,那麼這些數也一定是prime[j]的倍數,因此一定會在後面被prime[j]篩一次,所以就沒必要多篩了。」

這是我的回答,其實已經很詳細了。

再略微展開一點點,詳細一點點。

首先,我們是怎麼篩掉合數的呢?假設要篩掉1到n範圍內的所有合數,首先列舉的是最外層的i從2到n,如果列舉到i時發現i沒有被篩掉,則說明i為素數,存到prime陣列同時cnt++。然後,對於每個i,再通過從小到大列舉當前已知的素數,篩掉這些素數的i倍,假設沒有break,這樣顯然可以篩掉指定範圍內的所有合數,因為每個合數都一定可以表示為乙個素因子和另乙個數相乘的形式,而每個素數的所有在n範圍內的倍數的數都被篩了,即所有1到n範圍內的合數都被篩掉了。

沒有break的缺點是很顯然的——絕大部分合數都被篩了不只一遍,比如12會在i=4,prime[j]=3時篩一次,還會在i=6,prime[j]=2時被篩一次。

那麼怎麼才能做到使每個合數只被篩一次呢?這就是break的妙處了。

素數篩法(素數篩 線性篩)

求素數的方法在現階段可以總結為三種 這種方法最為簡單但效率太低,經過優化時間複雜度最低是o n sqrt n 輸入乙個n,輸出n以內所有素數 include intprime int n if flag 0 優化 printf d i intmain 素數篩法原理 2是素數,那麼2的所有倍數都是合數...

素數線性篩

ps 證明 神牛部落格。include include using namespace std const int n 100100 int v n p n n,m,tot int main 首先,先明確乙個條件,任何合數都能表示成一系列素數的積。不管 i 是否是素數,都會執行到 關鍵處1 如果 i...

線性篩素數

如題,給定乙個範圍n,你需要處理m個某數字是否為質數的詢問 每個數字均在範圍1 n內 輸入格式 第一行包含兩個正整數n m,分別表示查詢的範圍和查詢的個數。接下來m行每行包含乙個不小於1且不大於n的整數,即詢問該數是否為質數。輸出格式 輸出包含m行,每行為yes或no,即依次為每乙個詢問的結果。in...