【数学】PollardRho算法

这个是整数分解PollardRho算法。不是离散对数PollardRho算法,在竞赛里面离散对数一般使用BSGS算法解决,虽然消耗一些空间,但是复杂度稳定。

快速乘可以替换成其他正确形式的乘法。
MR可以适当去掉一些,例如只使用2,7,61。

每次调用PR返回其中一个非1的因子,所以在外面套一层getFactor返回其中一个非平凡因子。

对速度有要求时应该只对超过线性筛范围的数字进行getFactor。

不要直接调用PR,对质数调用PR会直接死循环。(MR算法只会把强伪质数误判为质数,不会导致PR算法TLE)

ll qmul(ll a, ll b, ll mod) {
    return (__int128)a * b % mod;
}

ll qpow(ll x, ll n, ll mod) {
    if(x >= mod)
        x %= mod;
    ll res = 1;
    while(n) {
        if(n & 1)
            res = qmul(res, x, mod);
        x = qmul(x, x, mod);
        n >>= 1;
    }
    return res;
}

namespace MillerRabin {

    // private
    bool MR(ll n, ll p) {
        for(ll k = n - 1; k; k >>= 1) {
            ll t = qpow(p, k, n);
            if(t != 1 && t != n - 1)
                return false;
            if((k & 1) == 1 || t == n - 1)
                // probably true
                return true;
        }
        // probably true
        return true;
    }

    // public
    bool isPrime(ll n) {
        if(n <= 1)
            return false;
        if(n <= 3)
            return true;
        if(!(n & 1))
            return false;
        static int basePrime[5] = {2, 3, 7, 61, 24251};
        for(int i = 1; i <= 5; ++i) {
            if(n == basePrime[i - 1])
                return true;
            if(!MR(n, basePrime[i - 1]))
                return false;
        }
        if(n == 46856248255981LL)
            return false;
        // probably true
        return true;
    }

}

using namespace MillerRabin;

namespace PollardRho {

    // private
    ll PR(ll n) {
        ll s = 0, t = 0, c = rand() % (n - 1) + 1;
        for(int i = 1;; i <<= 1, s = t) {
            ll p = 1;
            for(int j = 1; j <= i; ++j) {
                t = (qmul(t, t, n) + c) % n;
                p = qmul(p, abs(t - s), n);
                if(p == 0)
                    return n;
                if(j % 127 == 0) {
                    ll d = __gcd(p, n);
                    if(d > 1)
                        return d;
                }
            }
            ll d = __gcd(p, n);
            if(d > 1)
                return d;
        }
    }

    // public
    ll getFactor(ll n) {
        if(n <= 3)
            return n;
        if(!(n & 1))
            return 2;
        if(isPrime(n))
            return n;
        ll d = PR(n);
        while(d == n)
            d = PR(n);
        return d;
    }

}

using namespace PollardRho;
posted @ 2020-09-16 00:50  purinliang  阅读(586)  评论(0编辑  收藏  举报