模板:Miller-RabinPollard-Rho(数论)
所謂 pollard-rho,就是潑辣的肉
(逃)
前言
許多題解都把這兩個算法放在了一起。
那我也這樣辦吧!
miller-rabin可以在優秀的時間復雜度內完成對一個數的素性檢測。
而pollard-rho則是立足于Miler-rabin之上,可以在 O(n14)O(n^\frac 1 4)O(n41?) 的復雜度內分解出一個合數的非平凡因子。
Miller-rabin
費馬定理:若 ppp 為質數,那么 ap≡a(modp)a^p\equiv a\pmod pap≡a(modp),如果 a⊥pa\perp pa⊥p,同時也有 ap?1≡1(modp)a^{p-1}\equiv 1\pmod pap?1≡1(modp)。
那么一個樸素的思想是隨便找一個 aaa,看是否有 ap?1≡1(modp)a^{p-1}\equiv1\pmod pap?1≡1(modp)。
但是,費馬定理的逆定理并不成立,因此這個算法是很容易掛掉的,事實上,存在一類合數 nnn,對于任意的 a⊥na\perp na⊥n,都有 ap?1≡1(modp)a^{p-1}\equiv1\pmod pap?1≡1(modp),這類數被稱為卡邁克爾數。最小的卡邁克爾數為 561561561,已經可以證明,卡邁克爾數的數量是無窮個的。
我們需要更強的判斷方法。
二次檢測定理:如果 ppp 為質數,那么 x2≡1(modp)x^2\equiv1\pmod px2≡1(modp) 的兩個解分別為 x≡1(modp)x\equiv1\pmod px≡1(modp) 和 x≡?1(modp)x\equiv-1\pmod px≡?1(modp)。
證明:移項得 (x+1)(x?1)≡0(modp)(x+1)(x-1)\equiv 0\pmod p(x+1)(x?1)≡0(modp),由于 ppp 是質數,所以要使等式成立,只能是兩個括號中的一個等于 000。
反過來,如果對于一個 x≠±1(modp)x\ne\pm1\pmod px?=±1(modp),出現了 x2≡1(modp)x^2\equiv 1\pmod px2≡1(modp),那么 ppp 一定不是一個素數。
所以,我們考慮對于所有的奇素數 ppp(222 可以特判),p?1p-1p?1 都可以寫成 a?2k(a%2=1,k>0)a\cdot 2^k(a\%2=1,k>0)a?2k(a%2=1,k>0) 的形式,那么我們就可以把原來的式子變一下形:
xp?1≡1(modp)xa?2k≡1(modp)(xa?2k?1)2≡1(modp)x^{p-1}\equiv1\pmod p\\x^{a\cdot2^k}\equiv 1\pmod p\\(x^{a\cdot2^{k-1}})^2\equiv 1\pmod pxp?1≡1(modp)xa?2k≡1(modp)(xa?2k?1)2≡1(modp)
那么就出現了一個可以使用二次探測的形式,我們檢查一下 xa?2k?1x^{a\cdot2^{k-1}}xa?2k?1 是否為 ±1\pm1±1 即可。同時,注意到,如果 k>1k>1k>1 且 xa?2k?1x^{a\cdot2^{k-1}}xa?2k?1 依然等于 111,那么我們可以遞歸的進行多次二次探測。
雖然正確性大大提高,這個算法依然是一個概率性檢測。我們需要多選取幾個 aaa,多次檢測才能盡可能的保證其正確性。
實踐表明,選取前 121212 個質數已經可以保證 n=264n=2^{64}n=264 以內的正確性了。
注意! 費馬定理的前提是 a⊥pa\perp pa⊥p,因此,如果 a=pa=pa=p,會把 ppp 錯判成合數,需要特判。
int p[13]={0,2,3,5,7,11,13,17,19,23,29,31,37}; bool check(ll a,ll n){ ll k=n-1;if(ksm(a,k,n)!=1) return false;while(1){k>>=1;ll x=ksm(a,k,n);if(x!=1&&x!=n-1) return false;if(x==n-1||(k&1)) return true;} } bool prime(ll n){//miller-rabinif(n<3||((n&1)==0)) return n==2;for(int i=1;i<=12;i++){if(p[i]==n) return true;if(!check(p[i],n)) return false;}return true; }Pollard-Rho
感謝 _slb\text{\_slb}_slb 和 Asta\text{Asta}Asta!
(不會打紅黑名湊活看吧)
既然弗洛伊德找環慢的一批,我就不浪費大家時間,直接講倍增優化了。畢竟這兩個算法前后也并不構成前置關系。(甚至感覺倍增更好理解一些)
考慮一個隨機數列:
xi≡xi?12+c(modp)x_i\equiv x_{i-1}^2+c\pmod pxi?≡xi?12?+c(modp)
其中 ccc 為一個隨機常數。
這是一個很差的隨機數實現,只要某一項出現相同,就會陷入循環節。
生日悖論告訴我們,它的循環節期望長度是 O(n)O(\sqrt n)O(n?) 。
這個函數會在有限次后進入循環節,也就是:
這個樣子(圖源:oiwiki-分解質因數)
假設我們已經通過某種方式(比如 Miller-rabin) 知道了 nnn 是一個合數。
那么一定存在一個 mmm,滿足 m∣n,m≤nm|n,m\le \sqrt nm∣n,m≤n?。
那么這個函數在 modm\bmod \space mmod?m 的意義下的期望循環節長度就是 O(m)≤O(n14)O(\sqrt m)\le O(n^\frac 1 4)O(m?)≤O(n41?)。
modn\bmod \space nmod?n 意義下的環和 modm\bmod \space mmod?m 意義下的小環是同時存在的,大概就長成這樣:
不難看出,這張圖是我手畫的。
其中黑線代表的是 modn\bmod\space nmod?n 意義下的環(暫且叫它大環),紅線是 modm\bmod \space mmod?m 意義下的環(暫且叫它小環)。
那么我們要做的就是找到這個紅線的環。
如何尋找?gcd?\gcdgcd!
在函數上設置兩個指針 sss 和 ttt,先讓 ttt 不斷的往后移(具體而言,就是令 t←f(t)t\gets f(t)t←f(t))。然后計算 gcd?(∣t?s∣,n)\gcd(|t-s|,n)gcd(∣t?s∣,n)。若 gcd?(∣s?t∣,n)>1\gcd(|s-t|,n)>1gcd(∣s?t∣,n)>1,說明找到了一個 nnn 的因子(或者說 s?ts-ts?t 恰好是一個 modm\bmod \space mmod?m 意義下的環),就返回結果。
但是我們發現,如果 sss 在 f(0)f(0)f(0) 點處待著不動彈,可能 ttt 怎么移動都沒有用啊…
所以我們還需要時不時的把 sss 往前挪一挪。
還有一個問題:雖然我在這里把兩個環叫做大環、小環,但是它們的大小關系只是在期望的意義下,也就是說,是有可能存在 modn\bmod\space nmod?n 意義的環比 modm\bmod\space mmod?m 的環要小的。
這個時候,兩個指針還沒繞完小環,就把大環繞完了。那么具體來說會出現什么情況?就是 ∣t?s∣≡0(modn)|t-s|\equiv0\pmod n∣t?s∣≡0(modn),這個時候 gcd?(0,n)\gcd(0,n)gcd(0,n) 會直接返回 nnn,那么這個時候我們就重新選擇 ccc,重新跑就可以了。少俠請重新來過!
具體實現上,我們發現每次都求一遍 gcd?\gcdgcd 慢的一批,怎么辦?我們可以把每次得到的 ∣s?t∣|s-t|∣s?t∣ 都結果累乘再一起,隔一段時間一起算就可以啦!
累乘在一起太大了怎么辦?沒關系,偉大的歐幾里德告訴我們: gcd?(a,n)=gcd?(amodn,n)\gcd(a,n)=\gcd(a\bmod n,n)gcd(a,n)=gcd(amodn,n),所以過程中取模就可以了。
那么我們具體要隔多長時間呢?間隔太短可能沒啥效果,間隔太大可能明明早都出現了可以返回的結果,但你的代碼還在傻傻的移動 ttt 指針,反而變得很慢。為了和倍增的實現更好的適應,我們最好選擇形如 2k?12^k-12k?1 的間隔,而事實是:間隔設為 127127127 口感最佳!
說了這么多,總于可以請出我們潑辣的肉的完整代碼了!=v=
ll PR(ll n){//pollard-rhoc=rand()%(n-1)+1;ll s(0),t(0);ll val(1);for(int goal=1;;goal<<=1,s=t,val=1){//倍增for(int stp=1;stp<=goal;stp++){t=f(t,n);val=val*Abs(t-s)%n;if(stp%127==0){ll d=gcd(val,n);if(d>1) return d;}}ll d=gcd(val,n);if(d>1) return d;} } ll findfactor(ll x){ll p=x;while(p>=x) p=PR(x);//多次尋找return x; }總結
以上是生活随笔為你收集整理的模板:Miller-RabinPollard-Rho(数论)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑卡顿时不要暴躁!从这4个方面着手,运
- 下一篇: 洛谷P2056:[ZJOI2007]捉迷