素數判定 暴力到高效

2022-07-30 05:27:13 字數 3343 閱讀 7988

在平常做數論的題時,大部分都要涉及到判定(篩)素數吧,而今天我將給大家展示不同演算法的判定(篩)素數方法.....例題:

p3383 【模板】線性篩素數

這個比較暴力,直接從2列舉到n-1,再看能不能整除判斷即可,也就是看這個數除了1和自己本身還有沒有其他的因數

bool prime(int

n);

時間複雜度是o(n)

但是當n較大的時候,肯定會超時啊,所以我們需要一些優化

我們可以看出,因數總是成對出現的,而一對的兩個數,都以sqrt(n)為分界線,一邊乙個(除了sqrt(n)自己),所以我們只需要從2列舉到sqrt(n)即可

1

bool prime(int

n);2

時間複雜度是o(sqrt(n))

雖然已經很優了,但是直到我開啟了洛谷題解。

我們來看看質數分布的規律:大於等於5的質數一定和6的倍數相鄰。例如5和7,11和13,17和19等等;

證明:令x≥1,將大於等於5的自然數表示如下: ......6x-1,6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1............

可以看到,不在6的倍數兩側,即6x兩側的數為6x+2,6x+3,6x+4...由於2(3x+1),3(2x+1),2(3x+2),

所以它們一定不是素數,再除去6x本身,顯然,素數要出現只可能出現在6x的相鄰兩側。

所以,基於以上條件,我們假如要判定的數為n,則nn必定是6x-1或6x+1的形式,對於迴圈中6i-1,6i,6i+1,6i+2,6i+3,6i+4其中如果n能被6i,6i+2,6i+4整除,則n至少得是乙個偶數,

但是6x-1或6x+1的形式明顯是乙個奇數,故不成立;另外,如果n能被6i+3整除,則n至少能被3整除,

但是6x能被3整除,故6x-1或6x+1(即n)不可能被3整除,故不成立。綜上,迴圈中只需要考慮6i-1和6i+1的情況,

即迴圈的步長可以定為6,每次判斷迴圈變數k和k+2的情況即可**自洛谷題解第一篇)

**如下

1

bool prime(intx)2

10return

true

;11 }

時間複雜度是o(sqrt(n)/3)

所以作為最基本的小白,這種判定還是要掌握的

(思路**自

這個演算法是由miller和rabin根據費馬測試優化過來的(費馬小定理的逆定理)

a^(p-1)≡1(mod p)

都知道,只有p為質數才成立,然後很尷尬的341就出來了,雖然滿足以2為底的費馬小定理,但是.....341=11*31

然後,他倆閒著沒事就......

有乙個叫二次探測定理的東西,可以有效地提公升費馬小定理的正確性。如果對於素數p

'>p

,有正整數x

<

p'>x≡1

(modp)

'>x2≡1(modp)

;可以推得x2−

1≡0(

modp)⇒

p|x2

−1⇒p

|(x−

1)(x

+1)'>x2−1≡0(modp)⇒p|x2−1⇒p|(x−1)(x+1)

而x<

p'>x,所以如果p|(

x−1)

'>p|(x−1)

的話,x−1

=0,x

=1'>x−1=0,x=1

,或p|x+

1'>p|x+1

,則x=p−

1'>x=p−1

。因此,就有了miller-rabin測試。

有了二次探測定理,我們試著進行341的以2為底的費馬測試。2

340≡1(

mod341

)'>2340≡1(mod341)

如果341是素數,那麼也滿足二次探測定理,也就是2

170≡1(

mod341

)'>2170≡1(mod341)

而170還是個偶數,可以繼續進行二次探測定理。這時它就涼了,因為285≡

32(mod341

)'>285≡32(mod341)

,而它沒有通過二次探測定理,所以341不是個素數。

同時,因為費馬小定理沒有要求底為什麼,所以只以2為底肯定會放過一些漏網之魚,我們應該多選一些數為底,這樣才能使判斷的正確性提高。不過這個底最好選擇素數(不知道為什麼,可能與答案的模數大都為質數一樣吧...),來保證正確性。同時,在學習這個演算法時,網上會有一寫神奇的結論,比如選3個特定的底2,7

,61'>2,7,61

,就可以通過小於4

,759

,123

,141

'>4,759,123,141

的所有素數的測試,而選lat

ex2,

3'>latex2,3

為底,可以通過1

,373

,653

'>1,373,653

以內的測試。因此很多人都喜歡隨機幾個數作為底,而題目給出的質數也不一樣,這就是靠碰運氣了。不過上面分析過,它的錯誤率只有約4−k

'>4−k

,所以出題人在不知道你的底數的情況下,正確率是特別高的。

1 #include2

#define ll long long

3using

namespace

std;

4long

long

pow(ll x,ll y,ll p)515

return

ans;16}

17bool

check(ll x,ll y,ll p)

1825

bool

mr(ll x)

2632

intmain()

3342

return0;

43 }

任意整數x的倍數都不是素數

我們可以從小到大列舉n以內的質數,對不超過n的倍數進行標記剩下未標記的數即為質數。

1

for(int i=2;i<=b;i++)

2

但是乙個數可能被多個質數重複標記,所以我們從i*i開始列舉

1

for(int i=2;i<=b;i++)

2

時間複雜度為o(n*loglogn),效率已經接近線性

1

for(int i=2;i<=n;i++)28

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

913 }

素數判定 暴力法

總綱指路鏈結 在學習git的同時建立了乙個github倉庫,在這裡,指路。1.1 演算法描述 假設要判斷n是否為素數 判斷n是否還有除1和本身之外的因子 該方法的主要思路就是從2開始遍歷到n 1,檢視是否可以被n整除,如果找到乙個可以整除,那麼n為合數 如果沒有找到可以整除的,那麼n為素數。1.2 ...

素數判定,素數篩

這些零碎的知識點每個都學過n次了,但隔一段時間就會忘,記錄下來 素數定義 只能被自身和1整除的大於1的正整數 通過這個定義,我們就可以得出判斷素數的 這裡用到了cmath中的sqrt函式,其原型為double sqrt double 所以在取上界的時候,為了避免double帶來的精度丟失,寧可多列舉...

素數判定總結

1.對於百萬級別,判斷單個數是否為素數,用埃拉託斯尼斯篩法打乙個判斷是否為素數的表預處理一下。const int n 2000000 bool isprime n void doprime bool solve int64 l,int64 r,int64 a,int64 b,int64 c,int6...