在平常做數論的題時,大部分都要涉及到判定(篩)素數吧,而今天我將給大家展示不同演算法的判定(篩)素數方法.....例題:
p3383 【模板】線性篩素數
這個比較暴力,直接從2列舉到n-1,再看能不能整除判斷即可,也就是看這個數除了1和自己本身還有沒有其他的因數
bool prime(intn);
時間複雜度是o(n)
但是當n較大的時候,肯定會超時啊,所以我們需要一些優化
我們可以看出,因數總是成對出現的,而一對的兩個數,都以sqrt(n)為分界線,一邊乙個(除了sqrt(n)自己),所以我們只需要從2列舉到sqrt(n)即可
1bool 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的情況即可**自洛谷題解第一篇)
**如下
1bool 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的倍數進行標記剩下未標記的數即為質數。
1for(int i=2;i<=b;i++)
2
但是乙個數可能被多個質數重複標記,所以我們從i*i開始列舉
1for(int i=2;i<=b;i++)
2
時間複雜度為o(n*loglogn),效率已經接近線性
1for(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...