1. 程式人生 > >Pollard的rho啟發式因子分解演算法 & [CodeVS 4939] 尤拉函式:Miller-Rabin + Pollard-rho 質因數分解

Pollard的rho啟發式因子分解演算法 & [CodeVS 4939] 尤拉函式:Miller-Rabin + Pollard-rho 質因數分解

Pollard的rho啟發式因子分解演算法用於給出整數的一個因子。在一定的合理假設下,如果n有一個因子p,可在O(p)的期望時間內可找出n的一個因子p。

關於其複雜度,Wikipedia是這樣敘述的:

If the pseudo random number x = g(x) occurring in the Pollard ρ algorithm were an actual random number, it would follow that success would be achieved half the time, by the Birthday paradox in O(p^(1/2)) ≤ O (n^(1/4)) iterations. It is believed that the same analysis applies as well to the actual rho algorithm, but this is a heuristic claim, and rigorous analysis of the algorithm remains open.

以下絕大部分來自《演算法導論》。

Pollard-rho演算法的核心是用遞推式xi+1=(x2i+c)modn生成一個最終會進入迴圈的“隨機”序列(表示成有向圖,看起來就像ρ,這就是演算法名字的由來)。雖然只顯式地生成了一個序列,實際上同時生成了許多形如ρ的序列(後面將會推證);只要兩個指標都進入某個ρ的圈圈裡,把它們所指向的值作差,取絕對值,和n求gcd,就能得到n的一個因子。

虛擬碼如下:

Pollard-Rho(n, c)
    i = 1
    k = 2
    y = x = a random integer in [0, n)
    d = 1
    while
d == 1 i = i+1 x = (x*x+c) mod n if x == y return n d = gcd(n, abs(x-y)) if i == k k = k*2 y = x return d

它的正確性是顯然的。演算法可能會失敗地返回一個平凡因子n,也可能成功地返回一個n的某個非平凡因子。

xi+1=(x2i+c)modn的迴圈大小為C,迴圈的第一項是xt,進入迴圈後的某一時刻,k會被賦予一個不小於C的值,此時的x被儲存為y,再轉一圈,y固定不動,x會回到y,演算法以失敗終止。

必有2的某次冪落在區間[t, 2t]內,因此在不超過第2t步,迴圈內的某個值將被儲存。此時的k可能小於C,無妨,因為必有2的某次冪落在區間[C, 2C]內,2C步之內,有k不小於C成立。於是,至多走(2*min(t, C)+C)步,演算法終止。這個演算法叫Brent判圈演算法(Brent’s cycle finding method),與Floyd判圈演算法均為線性,但常數優於後者(至少3C次計算後繼結點)。根據Wikipedia,Pollard的原始版本採用Floyd判圈演算法,後來由Richard Brant用自己新發明的判圈演算法加以改進。

設n有一個因子p,其實我們同時在計算xi=ximodp,並且遞推式具有相同的形式:

xi+1=xi+1modp=(x2i+c)modnmodp=(x2i+c)modp=((ximodp)2+c)modp=(x2i+c)modp

同樣是ρ形。迴圈內兩個數作差,是p的倍數,和n取gcd,因子p或p的某倍便被呈現出來。與上面的論證類似,進入迴圈後不超過t步,迴圈內的某個值將被儲存,下一步,p被呈現。顯然ttCC

假設{xi}是隨機的,則tC都是O(p)的。

生日悖論:從n個數中可重複地隨機選擇k個,當k2n時,存在兩數相等的概率大於1/2。

用數學期望描述這個命題:相等數對的數目不少於1。這樣計算起來會簡單一些。

1i<jk定義指示器隨機變數Xij=I{ij},則E[Xij]=1n

E[i=1kj=i+1kXij]=i=1kj=i+1kE[Xij]=i=1kj=i+1k1n=k(k1)2n
令上式1,得到一個充分條件k2n

把這個結論運用到我們的問題中來。t=O(p)C=O(p)

至此,一切都看起來很美好。如果n有某個因子p,則