Pollard-Rho 總結

將一個大數\(N\)分解質因子。
試除法,暴力枚舉\(1~\sqrt{N}\)的數。時間複雜度:\(O(\sqrt{N})\)
通常,這個複雜度夠了,但有時,\(N\leq10^{18}\)
這就需要Pollard-Rho了。

首先,考慮一種簡單情況。設\(N=p*q(p<q)\)
有一種糟糕的做法:隨機法。隨機一個\(1~\sqrt{N}\)的數x,判斷能否整除。期望需要\(\sqrt{N}\)次。
我們發現,隨機的數x並不一定要等於p,只要是p的倍數即可,即\(gcd(N,x)=p\)
然而,這樣每次的概率仍只有\(1/\sqrt{N}\)

我們來考慮這樣一種情況:在[1,1000]裏面取一個數,取到我們想要的數(比如說,42),成功的概率是多少呢?顯然是1/1000。
一個不行就取兩個吧:隨便在[1,1000]裏面取兩個數我們想辦法提高準確率,就取兩個數的差值絕對值。
也就是說,在[1,1000]裏面任意選取兩個數\(i,j\),問\(∣i−j∣=42\)的概率是多大?答案會擴大到1/500。
我們可以取\(\sqrt{p}\),即\(N^{0.25}\)個數,兩兩做差並與N求gcd。
但我們需要兩兩做差,複雜度會回去。

\(gcd(|a-b|,N)=p\),則\(a=b (mod p)\)(a不等於b)
然後,我們可以隨機生成一個序列,看看裏面是否有模p意義下相等的兩個數。
但是,我們不知道p,我們只能通過求\(gcd(|a-b|,N)\)的方法來判斷\(a=b (mod p)\)是否成立。就是說,我們只能判斷\(a=b (mod p)\)是否成立,不能知道\(a\%p\)的值。
這個序列,我們顯然可以\(rand\),但有一種更好的方法:
設序列\(A_i=f(A_{i-1})\),其中\(f(x)=x^2+y\)(y爲定值)。那麼,若\(a=b (mod p),f(a) mod p\)一定等於\(f(b) mod p\)。但rand就沒有這個性質。
換句話說,就是mod p後的數列出現了循環(原數列沒有循環)。
這樣,只要找到mod p後的數列的循環即可。(若用rand(),就需要等到原數列循環,複雜度就會退化爲\(\sqrt{N}\)
找循環可以用Floyd判圈,而這個算法正好是對兩個進行比較的。
但是,可能原數列循環後,都沒有找到解。
所以,在判圈的時候,如果原數列循環,則退出,換一個新的y計算。
根據“生日悖論”,只要選\(\sqrt{p}\)個小於p的數,就有相等的。
由於模數是\(10^{18}\)級別的,要用快速乘。
時間複雜度:\(O(N^{0.25}*logN)\)

代碼:

int sed[4]={13131,4649,65537,28627},se;
ll n;
ll gcd(ll a,ll b)
{
    while(b!=0)
    {
        ll t=a%b;
        a=b;
        b=t;
    }
    return a;
}
ll f(ll x)
{
    return (ksc(x,x,n)+se)%n;
}
ll ksc(ll a,ll b,ll md)
{
    ll jg=0;
    while(b>0)
    {
        if(b&1)
            jg=(jg+a)%md;
        a=(a+a)%md;
        b=(b>>1);
    }
    return jg;
}
ll rho()
{
    while(1)
    {
        se=sed[rand()%4];
        ll z1=1,z2=f(z1);
        while(z1!=z2)
        {
            ll t=z1-z2;
            if(t<0)
                t=-t;
            ll g=gcd(t,n);
            if(g!=1&&g!=n)
                return g;
            z1=f(z1);
            z2=f(f(z2));
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章