(數論三)素數原理

2021-08-29 14:07:47 字數 2429 閱讀 8471

​ 打算寫一下自己對acm中常用到的數論知識,加深鞏固和查缺補漏。

​ 在數學中,對於n>1,若n的因子只有1和它本身,那麼n就是質數,也稱作素數。而在acm中素數型別的題目是經常會碰到的。

​ 那麼我們可以怎麼判斷素數呢?

一.對於判斷單個n是否為素數,我們可以通過三種情況來判斷:

​ (1)用i遍歷2~ n -1,若n % i == 0就代表存在除1和它本身以外的因子,就直接跳出,若執行完就代表沒有其它因子,n為素數。時間複雜度為o(n)

​ (2) 我們可以優化(1),因為若存在大於sqrt(n)的因子k,那麼n / k 的值一定在 2 ~ sqrt(n)中。因此我們只需要用i遍歷2 ~ sqrt(n)即可,若n%i == 0就代表存在除1和它本身以外的因子,就直接跳出,若執行完就代表沒有其它因子,n為素數,時間複雜度為o(sqrt(n)) 。

​ (3) 我們繼續優化(2),若 n % 2 != 0,那麼從i從3~sqrt(n),只需要考慮奇數即可。因此時間複雜度為o(sqrt(n) / 2)

我給出(3)的**:

bool chooes(ll n) 

return true; //否則n為素數

}

二.對於判斷2~n每個數是否為素數,我們應該怎麼辦呢?

​ 我們利用一中最快的(3)方法,時間複雜度為o(n✖️sqrt(n) / 2),若n為1e5以上,1s之內是篩選不出來的。因此我們只能想別的辦法,先來介紹第一種:

(1)由於是求2~n的每個數,因此我們可以嘗試利用之前已經判斷過的數來求後面的數是否為素數。我們知道,素數的因子只有1和它本身,那麼乙個2以上的數的倍數一定不是素數!!又因為合數一定可以由素數累乘得到,所以我們只需要把所有素數的倍數標記為合數,剩餘的數一定是質數。

​ 也就是說,對於n = 10,素數2的倍數4,6,8,10一定是合數;

​ 素數3的倍數6,9一定是合數

​ 4是合數跳過,素數5的倍數10一定是合數;

​ 6是合數跳過,得到素數7

​ 由於8,9,10是合數,因此全部跳過

​ 我們就得到10以內的素數2,3,5,7

​ 通過這樣的辦法,我們可以在趨近於線性(實際是nlog(log(n))) 的時間內求出2~n中的每個數是否是素數。

​ 以上的第一種方法,是被埃拉託斯特尼發明的,因此也叫做埃篩法

​ 如果大家覺得還不夠快,趨近於線性也不是線性啊!!有沒有線性時間就能求出來2~n所有素數的方法呢?

​ 答案是有的,該方法稱為線篩。

(2)我們知道上面的數,對於素數2的倍數4,6,8,10一定是合數;

​ 對於素數3的倍數6,9一定是合數;

​ 大家有沒有發現6此時兩次被判定為合數,埃篩之所以不是線性的原因就在於這裡。。它可能會造成合數的重複判定。我們怎麼樣才能每個數隻判定一次呢?就是在這個合數的最小素因子時判定該數為合數,其它素因子時不判定,這樣就可以保證每個合數只判定一次了。這也就是線性篩的精髓了:

​ 對於2,我們判定為素數,我們檢索已經存在的素數2,把2✖️2,也就是4標記為合數;

​ 對於3,我們判定為素數,我們檢索已經存在的素數2, 3,把2✖️3,3✖️3,也就是6, 9標記為合數

​ 對於4已標記為合數,我們檢索已經存在的素數2,3,把2✖️4,也就是8標記為合數,由於4 % 2 == 0,因此我們直接跳出,不再執行3✖️4也就是12的判定(因為它可以由2✖️6判定,2是12的最小素因子)

​ 對於5,我們判定為素數,我們檢索已經存在的素數2,3,5,把2✖️5,3✖️5,5✖️5,也就是10,15,25標記為合數

​ 對於6已標記為合數, 我們檢索已經存在的素數2,3,5,把2✖️6,也就是12標記為合數,由於6 % 2 == 0,因此我們直接跳出,不再執行3✖️6也就是18的判定(因為它可以由2✖️9判定,2是18的最小素因子)

​ 就不往下繼續寫了,通過以上的流程,我們就可以判定2~n中的每個數是否為素數並保證每個數隻判定一次(還可以加如果兩數相乘大於n直接跳出等限制條件),這樣時間複雜度就是o(n)

我給出(2)方法的實現**:

#include #include #define ll long long

#define n 100005

bool book[n + 5]; //book[i]判斷i是否為素數

int prime[n + 5]; //prime陣列儲存2~n全部素數,若mle可改小該陣列長度

void init()

for (int j = 1; j <= prime[0] && (ll)prime[j] * i <= n; j++)

}return;

}int main ()

​ 以上就是素數判定和素數篩的一些理論與模版。在acm中關於素數的題目很活,變形也很多,大家有興趣可以看一下我部落格中的數論標籤的題目,裡面有很多基於素數篩框架的變形題目~

如果有寫的不對或者不全面的地方 可通過主頁的****進行指正,謝謝

數論 素數測試

檢查乙個正整數是否是素數稱作素數測試。基本素數判別法 正整數n是素數,當且僅當它不能被任何乙個小於根號n的素數整除 埃拉託斯尼斯篩法 先把n個自然數按次序排列起來。1不是 質數,也不是 合數,要划去。第二個數2是 質數留下來,而把2後面所有能被2 整除的數都劃去。2後面第乙個沒劃去的數是3,把3留下...

數論之 素數

素數又叫質數,乙個數除了1和他本身沒有其他因子的叫素數。最一般的判斷素數寫法 bool prime int x return true 快點的n開平方的複雜度bool prime int x 這是開平方的寫法,減小了查詢範圍。return true bool prime int x 這是乘的寫法,讓...

數論1 素數 約數 反素數

素數是指只能被自身整除和被1整除的數 大於1的自然數,1不是素數 不是素數的數為合數 常見的題型有 素數的判定 素數的篩選兩種題型 素數的篩選 const int n 1000001 int primes n cnt primes存素數 cnt 存素數的個數 bool st n 存數n是否被篩過 v...