尤拉篩 素數 素數個數

2021-10-02 07:34:54 字數 1361 閱讀 3246

素數個數

題目描述:

求1,2,\cdots,n1,2,⋯,n 中素數的個數。

輸入輸出格式

輸入格式:

1 個整數n。

輸出格式:

1 個整數,表示素數的個數。

輸入輸出樣例

輸入樣例#1: 複製

10輸出樣例#1: 複製4說明

• 對於40% 的資料,1 \n \10^6

• 對於80% 的資料,1 \ln \10^7

• 對於100% 的資料,1 \n \10^8

當看到這道題的時候,我直接寫下了逐個取餘判斷的**,然而看到資料範圍的時候我就慌了。。。

當時由於沒學過關於素數篩選的演算法,很顯然除了打表我什麼也幹不了。。。

好吧,不廢話了,直接步入正題:

由於這道題的資料範圍較大,因此列舉肯定是行不通的,就算是使用正常篩法,面對10的八次方的資料也是顯得十分的吃力,由此,我們要引入尤拉篩法(這裡先介紹一下樸素篩法):

由於任何合數都可以拆分成若干素數的乘積,因此每當我們找到乙個素數的時候,就可以將部分合數篩選出來,那麼我們就解決的部分的問題。

並且講到這裡有乙個隱含條件:就是沒有被篩選出來的數就是素數(這個可以簡化**長度,也是理解這道題的關鍵),至於證明,我們可以用反證法:如果它不是素數,那麼它一定是合數,而合數又可以拆分成兩個素數的乘積,那麼在找到它的因子的時候就一定會將其篩選出來。 證完

強忍著沒有在證明的時候說顯然。。。

因此我們要優化!!!(由此誕生了尤拉篩法)

由於下面講解問題,我們先看**:

#include

#include

int prime[

100000005];

bool vis[

100000005];

intprime

(int n)

}return ans;

}int

main()

其實也很好理解:由於合數可以拆分成不同素數*k(k∈z),那麼當我們篩選時只要篩選出最小素數因子即可,比如12

12=43=62 很顯然,我們需要的就是用素數2來篩選掉12,那麼怎麼實現呢?

其實這其中有乙個規律:由於i是由小到大列舉的,並且陣列中的素數也是由小到大列舉的,那麼顯然我們會先看到43,又因為4在和素數2篩掉8時發現竟然能被整除,並且接下來的43是沒有意義的計算,那麼每當i%素數==0是跳出即可。

如果你要問我具體該如何證明那我可以簡單說一下:

由於p[j]*k(k∈z)=i,那麼a[j+1]*i=a[j]ka[j+1],所以a[j]乘以某個數一定在將來會把這個合數篩掉,由於a[j]比a[j+1]小,那麼a[j]才可能是最小素數因子。

線性篩素數(尤拉篩)

尤拉篩是o n 複雜度的篩素數演算法,1秒內埃篩能處理1e6的資料,而1e7的資料就必須用尤拉篩了。埃篩的基本思想是 素數的倍數一定是合數。尤拉篩基本思想是 任何數與素數的乘積一定是合數 演算法概述 遍歷 2,n 的所有數i,內層迴圈遍歷已經找到的素數prime j 將i prime j 標記為合數...

素數判定(素數篩法)(尤拉)

這裡主要說一下素數篩法,該方法可以快速的選取出1 n數字中的所有素數。時間複雜度遠小於o n sqrt n 方法為 從2開始,往後所有素數的倍數都不是素數。最後剩下的數都是素數。再說說尤拉公式,用來解決所有小於n中的數字有多少個與n互質,用 n 表示。n n 1 1 q1 1 1 q2 1 1 qk...

尤拉篩 素數 基礎

求乙個數是不是素數,我們最開始用到的方法是從2開始跑到這個數的前一項,如若這些數都不能被這個數整除,那麼就稱這個數是素數 素數的概念是除了1和它本身之外不再有其他因數 除了1 我們稱這樣的數為素數。如果我們就按一般思路去實現求解這個數是不是素數,那麼會用for迴圈從2開始跑到這個數的前一項,每個數都...