線性篩素數

2022-05-26 03:30:11 字數 1652 閱讀 3959

比如想求10000以內的素數,定義表int a[10000],進行線性篩選後,a[n]的值就代表n是不是素數,a[n]如果是1,就代表n是素數,a[n]如果是0,就代表n不是素數,這就是查表。再判定其他的素數也是一樣,不用再做任何計算。

而如果用遍歷取餘,那麼每判定乙個數都要從頭開始再遍歷一遍,而線性篩法只在開始一次性運算完,以後只要查表即可,查表通常只需要1條語句。所以如果你的程式從始至終只需要判定那麼幾次素數那麼用遍歷取餘即可,但是如果需要多次判定素數,而且這個數還不是很小的話,那麼線性篩法就會體現出巨大的優越性來。

該演算法的核心為:每個合數必有乙個不是他本身的最大因子,那麼如果我們用這個最大的因子去篩掉這個合數的話,那麼這個合數僅僅只會被篩掉一次,因為乙個數的最大因子是唯一的。我們設這個合數為a,它的最大因子為i,那麼存在乙個整數q使得:a=i*q .設i=p1*p2*p3*....pn,且p1到pn都是素數,那麼q必定是小於等於p1的乙個素數。這樣當i一定時,用所有符合條件的q乘上i,得到所有符合條件的a,把這樣的a全部篩去,就能不重複,不遺漏的線性篩素數。

證明同樣用以上的設定,則有a=i*q=p1*p2*p3*....pn*q,先證明q是乙個質數,假設q不是乙個質數,則設q=b*c,則b*i一定也是a的因子且一定比i大,與i是a的最大因子相矛盾,所以q一定是乙個質數;

在證明q一定小於等於p1,假設q大於p1,且p2*p3*....pn*q一定是a的乙個因子,又因為p2*p3*....pn*q>p1*p2*p3*....pn,所以p2*p3*....pn*q>i,與i是a的最大因子矛盾。

最後我們就可以得出結論:對於每乙個數i,乘上小於等於i的最小素因數的素數,就得到以i為最大因數的合數。設有乙個數t,只要將所有以比t小的數為最大因數的合數篩去,那麼比t小的數里剩下的就只有素數了。這就是線性篩法求素數的方法。

本文給出的證明方法並不是很嚴格,很不嚴密,但是本文只是想解釋線性篩素數的演算法,並不是想嚴格證明,如果想看嚴格證明請看數論中的證明。另上面提到的線性篩素數的另一種說法,其實到這裡讀者應該差不多明白了,任何乙個合數都可分解為乙個素數和另乙個數(不一定是素數還是合數)的乘積。我們既然找到了這個合數最大的因數,那麼根據上面結論裡另乙個乘上的素數必然就是他的最小素因數。有很多部落格說是用最小質因子來篩素數,但博主認為這樣不大好證明,到了這裡讀者也會發現其實和最大因子是一樣的。

程式設計實現:

題目 洛谷p5736 【深基7.例2】質數篩

**:

#include#include#include#include#include#include#include#include#include#include#include#include#include#define dd double

#define ll long long

#define ull unsigned long long

#define n 101

#define m 100001

using namespace std;

int n;

int a[n],pr[m],tail;

int vis[m];

int main() }

for(int i=1;i<=n;i++) if(!vis[a[i]]) printf("%d ",a[i]);

return 0;

}

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

求素數的方法在現階段可以總結為三種 這種方法最為簡單但效率太低,經過優化時間複雜度最低是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...