數論 多種素數判斷法及素數篩法

2022-05-22 17:45:11 字數 2806 閱讀 4171

水了一篇啊...

眾所周知,大於等於\(2\)的僅含有\(1\)和自身這兩個因子的正整數被稱作素數

故只要判斷在\([2,n-1]\)範圍內是否存在其它因子,就可以判斷\(n\)是否為素數了

無腦判斷法直接從\(2\)for到\(n-1\),稍微優化下可以縮減到\([2,\frac n 2]\),但這個方法時間複雜度為\(o(n)\)

可以發現,如果某個數\(x\)是\(n\)的因子,那麼\(\frac n x\)也一定是\(n\)的因子(可能\(x==\frac n x\))

所以如果將這兩個因子看作一組,我們其實只需要判斷\([2,\sqrt n]\)以內是否有素數即可,時間複雜度為\(o(\sqrt n)\)

#includebool isprime(int n)

bool isprime2(int n) //寫著比較方便,下面都用這種寫法

根據素數(\(≥5\))的分布性質可以得知

每個素數都與\(6\)的倍數相鄰

例如\(5,7\ ;\ 11,13\ ;\ 17,19...\)

所以得出的結論是,如果乙個\(≥5\)的數對\(6\)取模不等於\(1\)或者\(5\),那麼這個數一定不是素數

於是我們就能從\(5\)開始,以\(6\)為步數判斷到\(\sqrt n\)過,每次只需要判斷\(i\)與\(i+2\)是否為因子,大大提公升了判斷效率

時間複雜度小於\(o(\sqrt n)\)

bool isprime(int n)

下文將會闡述幾種篩法

通過\(o(n)\)、\(o(nloglogn)\)幾種不同時間複雜度篩出素數後實現\(o(1)\)查詢

但將會受限於空間

這是對於乙個不能在\(o(\sqrt n)\)時間範圍內判斷出是否為素數的大數的測試方法

通過選取小素數去測試被測數是否為素數

但非素數也有\(\frac 1 4\)的概率會通過檢測

所以需要多次選取不同素數進行測試,若都通過則大概率為素數

注:如果\(int\)範圍內的某個被測數用\(30\)以內的素數均能通過測試,可以得到該數為素數。

引理 1 ——費馬小定律:

設\(p\)是素數,\(a\)為整數,且\((a,p)=1\),則\(a^≡1\ (mod\ p)\)。

引理 2 ——二次探測定理:

如果\(p\)是乙個素數,且\(0,則方程\(x^2≡1\ (mod\ p)\)的解為\(x_1=1,x_2=p-1\)。

所以該演算法,流程如下

設\(s,t\)使得\(2^s*t=x-1\)(\(t\%2==1\))

取一小素數\(a\),算出\(a^t\),然後不斷平方並進行二次檢測(進行\(s\)次)

根據費馬小定律,如果\(a^\ !≡\ 1\ (mod\ p)\),則可得\(x\)非素數

多次進行檢測,可使得正確性概率更高

typedef long long ll;

int prim[20]=;

ll qmul(ll a,ll b,ll mod) //快速乘

return r;

}ll qpow(ll a,ll n,ll mod) //快速冪

return r;

}bool miller_rabin(ll x)

for(int i=0;i<10&&prim[i]該檢測方法常運用於大數因數分解pollard rho演算法中

基於樸素判斷法的樸素篩法

複雜度\(o(n^)\),很慢

bool prime[maxn];

bool isprime(int n)

void primeselect()

埃氏篩法是一種從\(2\)開始,通過質因子列舉的方式篩去所有合數,使得最後留下的均為素數

如果數字\(x\)是素數,那麼所有以\(x\)為因子的數均非素數(素數性質)

所以接下來可以列舉以\(x\)為因子的數並標記為合數即可

優化1:每次找到乙個素數\(x\),列舉下界可以是\(x^2\)而非\(2x\)(可證得),可小幅度縮短篩選時間

優化2:(根據優化1可得)素數列舉只要求到\(\sqrt n\)即可篩出\(1\)到\(n\)內的所有素數

時間複雜度\(o(nloglogn)\),較為高效(還好寫)

bool prime[maxn];

void primeselect(int n)

如需素數記錄,外層迴圈改為\(2\)到\(n\)即可

int prime[maxn],cnt=0;

bool vis[maxn];

void primeselect(int n)

}

可以發現,埃氏篩法雖然較為高效,但未經判斷直接開始列舉質因子的倍數則會產生一定數量的重複標記

重複對某些已經篩出的合數進行標記,只會浪費複雜度,這也正是其\(o(nloglogn)\)的由來(在一定程度上,\(loglogn\)已經非常高效)

但我們不滿足於這種看似高效的演算法,而需要真正意義上的線性篩

所以在埃氏篩法的基礎上,讓每個合數只被它的最小質因子篩選到一次即判斷退出,以達到不重複的目的

這便是尤拉篩法,時間複雜度\(o(n)\)

int prime[maxn+50],cnt=0;

bool vis[maxn+50];

void primeselect()

}}

素數判斷及篩法

單個素數判斷 素數判斷 小資料 int prime int n miller rabin 大素數判定 單個數字n複雜度15 log n int mr 30 此陣列為測試用的a,這12個可測所有的long long int lli miller rabin lli n if x 1 return fa...

素數判斷及篩法

素數 prime number 又稱質數,有無限個。素數定義為在大於1的自然數中,除了1和它本身以外不再有其他因數。問法1 給定乙個數n,判斷n是不是素數 一 暴力列舉 列舉2 n 1分別當做除數,判斷是否能整除,如果某個數能把n整除,那麼就說明n不是素數,如果所有都不能整除,那麼n就是素數。注 n...

素數判斷(篩法)

最簡單寫法 int isprime int n for int i 2 i n i return1 初步優化 乙個數的因數是成對出現的,其中乙個因數在開方後的前面乙個在開方後的後面,所以只需判斷它前面的數就可以了,如果前面都沒有,那麼它後面更不會有.這樣就可以減少迴圈次數.int isprime i...