int p[n]
, cnt;
//p[n]用來存質數,cnt表示質數的個數
bool st[n]
;//表示當前的數有沒有被篩過
樸素篩法 o(n
logn
)o(nlogn)
o(nlog
n)
void
get_primes
(int n)
由於當執行到 i 時可以確保已經用小於 i 的每乙個質數都篩過一遍,因此可以保證每乙個合數都會被篩掉
埃式篩法 o(n
logl
ogn)
o(nloglogn)
o(nlog
logn
) 在樸素篩法中,2 * 4 與 4 * 2 的結果都是8,因此乙個數可以用合數篩的時候,其實已經被質數已經篩過一次,所以可以只在 i 是素數的時候篩
void
get_primes
(int n)
}
由算術基本定理知一定可以將每乙個合數都篩掉(因為每乙個合數都能分成若干個質數)
線性篩法 o(n
)o(n)
o(n)
, n = 1e7時基本上就比埃式篩法快一倍
演算法核心:保證每個合數只會被其最小質因子篩掉
void
get_primes
(int n)
}
首先證明合數是不是一定會被篩掉
假設n是乙個合數,且p是n的最小質因子
故 有n
=p∗n
p故有n = p * \frac
故有n=p∗
pn只需要滿足p小於n
p\frac
pn,當 i 等於n
p\frac
pn時,n就會被篩掉
反證法,假設n
p\frac
pn小於p
如果n
p\frac
pn是質數,那麼n
p\frac
pn就是n的最小質因子,故n
p\frac
pn小於p不成立
如果n
p\frac
pn是合數,那麼由算術基本定理,n
p\frac
pn一定可以分出乙個比p小的素數來作為n的最小質因子,故n
p\frac
pn小於p不成立
綜上,p一定小於n
p\frac
pn,故每乙個合數肯定會被篩掉
其次證明是不是每個合數只會被其最小質因子篩掉
for
(int j =
0; p[j]
* i <= n; j ++
)
如果 i % p[ j ] == 0 說明p[ j ]是 i 的最小質因子(因為p[ j ]是從小到大列舉的), 所以p[ j ]也是 i * p[ j ]的最小質因子
如果 i % p[ j ] != 0 說明p[ j ]小於 i 的所有質因子(因為p[ j ]是從小到大列舉的),所以p[ j ]也是 i * p[ j ]的最小質因子
而至於為什麼要break,因為一旦 i % p[ j ] 為0時,說明p[ j ]是 i 的最小質因子,而此時如果繼續迴圈下去,用p[ j + 1 ] * i 篩時,由於 i 的最小質因子p[ j ]小於p[ j + 1],因此這時候被篩掉的合數就不是被他的最小質因子篩掉的了
所以break也是保證線性篩法時間複雜度的乙個重要原因~
深入理解線性素數篩 以後再也不用模板了
線性素數篩也算是一種基本的演算法吧,和揹包一樣,必須要做到深入理解其原理,並且能快速打出 來。兩個大前提 1.自然數中,1既不是素數也不是合數。小學知識 2.乙個合數一定能分解成乙個素數和另乙個數相乘。這個我不能證明,但是科學應該不會有錯 先從普通的思路談起。如果問你乙個數是不是素數,那你一定是fo...
找素數(質數) 線性篩法和埃氏篩法
先看這道題 洛谷p1217回文質數 對於這道題,普通的暴力模擬會tle,所以得尋求改進。這裡我學會了兩種方法 第一種 線性篩法 這種演算法的核心思想就是 任何乙個合數都可以由質數相乘得到 下面就是核心 吃透了核心 就可以在其中新增點細節,然後就可以拿去解決問題了 這裡需要開多大的陣列取決自己 boo...
小X的質數 NOIP模擬賽 魔改線性篩素數
題意 求 l r 範圍內是質數或兩個質數乘積的數的個數 魔改線性篩素數即可,預處理1 nmax的所有符合要求的數的數量,對於每組詢問 o 1 回答。對於每個素數,肯定是要計算的。在後面排除合數的時候,判斷當前數是不是素數,若是,也算入其中。用字首和優化,對於一組詢問 l,r 回答 cnt r cnt...