素數的篩法

2022-05-02 13:06:11 字數 3192 閱讀 4573

素數的篩法有很多種

在此給出常見的三種方法

以下給出的所有**均已通過這裡的測試

名字好長 :joy:不過**很短

思路非常簡單,對於每乙個素數,列舉它的倍數,它的倍數一定不是素數

這樣一定可以保證每個素數都會被篩出來

還有,我們第一層迴圈列舉到$\sqrt(n)$就好,因為如果當前列舉的數大於n,那麼它能篩出來的數一定在之前就被列舉過

比如說:

$\sqrt(100)=10$

不難發現我們從$20$列舉所篩去的數一定被$5$篩過

1 #include2 #include3

using

namespace

std;

4const

int maxn=10000001

;5 inline int

read()69

while(c>='

0'&&c<='

9') x=x*10+c-48,c=getchar();return x*f;10}

11int

vis[maxn];

12int

n,m;

13int

main()

1426

return0;

27 }

但是你會發現這份**只能得30分

看來這種演算法還是不夠優秀

下面我們來探索一下他的優化

另外,這種演算法的時間複雜度:$o(n*logn)$

根據唯一分解定理

每乙個數都可以被分解成素數乘積的形式

那我們列舉的時候,只有在當前數是素數的情況下,才繼續列舉就好

這樣可以保證每個素數都會被篩出來

果然,加了優化之後這種演算法快了不少

可以證明,它的複雜度為:$o(n*log^)$

這種演算法已經非常優秀了,但是對於1e7這種極端資料,還是有被卡的風險

那麼,還有沒有更快的篩法呢?

答案是肯定的!

我們思考一下第二種篩法的運算過程

不難發現,對於6這個數,它被2篩了一次,又被3篩了一次

第二次篩顯然是多餘的,

我們考慮去掉這步運算

1 #include2 #include3

using

namespace

std;

4const

int maxn=10000001

;5 inline int

read()69

while(c>='

0'&&c<='

9') x=x*10+c-48,c=getchar();return x*f;10}

11int

vis[maxn],prime[maxn];

12int tot=0;13

intn,m;

14int

euler()

1525}26

}27intmain()

2837

return0;

38 }

對於這份**,我們分情況討論

當$i$是素數的時候,那麼兩個素數的乘積一定沒有被篩過,可以避免重複篩

當$i$不是素數的時候

程式中有一句非常關鍵的話

if(i%prime[j]==0) break;
如果我們把$i$的唯一分解形式表示為$i = p_1^p_2^ \dots p_n^$

這句話可以保證:本次迴圈只能篩除不大於$*i$的數

這樣的話每個數$i$都只能篩除不大於$i$乘$i$的最小素因子的數

反過來,每個數只能被它的最小素因子篩去。

也就可以保證每個數隻會被篩一次(這一步好像不是很顯然,我在最後會給出證明)

舉個例子,

設$i=2*3*5$,此時能篩去$i*2$,但是不能篩去$3*i$

因為如果能曬出$3*i$的話,

當$i_2=3*3*5$時,篩除$2*i_2$就和前面重複了

另外為了方便大家直觀理解,給出一張圖表

這樣顯得直觀一些

上面的證明:我自己瞎yy的可能不是很嚴謹

現在我們需要證明$i = p_1^p_2^ \dots p_n^$只會被$p_1$篩去

那麼我們需要證明三個條件

1.$i$一定被$p_1$和$p_1^p_2^ \dots p_n^$篩除過

很顯然,在列舉到$p_1$之前不會有其他素因子使$p_1^p_2^ \dots p_n^$停止迴圈

2.$i$不會被$p_1^p_2^ \dots p_n^$篩去

同樣也很顯然,當列舉到$p_1$時就會停止迴圈

可以看出這種演算法的時間效率是非常高的!

時間複雜度:嚴格$o(n)$

在一般情況下,第二種篩法已經完全夠用。

第三種篩法的優勢不僅僅在於速度快,而且還能夠篩積性函式,像尤拉函式,莫比烏斯函式等。

這個我以後還會講的

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

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

篩法求素數 線性篩法求素數

2021年更新版 篩法求素數 線性篩法求素數 要理解篩法求素數首先要知道乙個定理,整數唯一分解定理 任意大於等於2的正整數都有且只有一種方式寫出其質因子的乘積表示式。a p1p2p3p4 pn pi是素數且pi pj eg 2 2 4 22 12 223 36 2233 也就是說任意乙個合數都能分成...

Eratosthenes篩法(素數篩)

最一般的素數篩思想很簡單,對於不超過maxx的每個非負整數p,刪除2p,3p,4p,然後剩下的就是素數,複雜度o nlogn 因為對內層迴圈n 2 n 3 n n 小於 1 1 2 1 3 1 n ln n 1 其中 為尤拉常數 0.577218 應當注意,1不是素數哦 這樣已經不慢,但由於所有非素...