【数学】BSGS算法

BSGS算法

求解 (a^xequiv b (mod m)) 其中 (gcd(a,m)=1)

随便取一个 (x_1) ,则可以把 (x) 通过 (x=kx_1-x_2) 替换,其中 (x_2<x_1) 。则 (a^{kx_1-x_2}equiv b (mod m))

(a^{kx_1}equiv bcdot a^{x_2} (mod m))

枚举 (x_2) 的值,算出所有的右边的情况,存到一个Hash表里面,使得可以通过 (bcdot a^{x_2}) 查到 (x_2) 的值。

然后 枚举 (k) 的值,可以很快得到 (a^{kx_1}) 的值,然后假如这个值存在于Hash表里,则说明某一个 (x_2) 和它匹配,返回当前的 (x=kx_1-x_2)

扩展BSGS算法

求解 (a^xequiv b (mod m))

namespace exBSGS {

    ll qmul(ll a, ll b, ll mod) {
        ll res = 0;
        while(b) {
            if(b & 1)
                res = (res + a) % mod;
            a = (a + a) % mod, b >>= 1;
        }
        return res;
    }

    ll qpow(ll a, ll n, ll m) {
        ll s = 1;
        while(n) {
            if(n & 1)
                s = qmul(s, a, m);
            a = qmul(a, a, m), n >>= 1;
        }
        return s;
    }

    // a^x = b mod m, gcd(b, m) = 1
    ll bsgs(ll a, ll b, ll m, ll k = 1, ll t = 0) {
        static unordered_map<ll, ll> M;
        M.clear();
        if(b == 1)
            return 0;
        ll B = ceil(sqrt(m)), s = b;
        for(ll i = 0; i < B; ++i, s = qmul(s, a, m))
            M[s] = i;
        s = k, k = qpow(a, B, m);
        for(ll i = 1; i <= B; ++i) {
            s = qmul(s, k, m);
            if(M.count(s))
                // minimum solution
                return i * B - M[s] + t;
        }
        // no solution
        return -1;
    }

    // a^x = b mod m
    ll exbsgs(ll a, ll b, ll m) {
        if(b == 1)
            // minimum solution
            return 0;
        ll k = 1, t = 0;
        for(ll d = __gcd(a, m); d != 1; d = __gcd(a, m)) {
            if(b % d != 0)
                // no solution
                return -1;
            ++t, b /= d, m /= d, k = qmul(k, a / d, m);
            if(b == k)
                // minimum solution
                return t;
        }
        // minimum solution
        return bsgs(a, b, m, k, t);
    }

}

离散对数

求解 (x^aequiv b (mod p))

这里 (p) 是一个质数,众所周知质数都有原根,找出最小的原根 (g)

有且仅有一个数 (cin[0,p-1)) ,使得 (x=g^c)

方法一:

原式变为 ((g^c)^aequiv b (mod p))

((g^a)^cequiv b (mod p))

那么把 (g^a) 视为 (a) ,把 (c) 视为 (x) ,问题就变成了 (a^xequiv b (mod p)) ,使用普通的BSGS算法求解。

原方程的一个特解是 (xequiv g^c (mod p))

方法二:
(x^aequiv b (mod p)) 视作 ((g^c)^aequiv g^t (mod p))

两边同时取离散对数,得 (caequiv t (mod varphi(p)))

那么用BSGS求出 (g^t equiv b (mod p))(t) ,然后变成一个线性同余方程问题,用exGCD求解。

找到所有解:

上面的方法找到一个特解,那么所有的解是这样找:

因为 (g^{varphi(p)}equiv 1 (mod p)) (原根的性质)

那么原方程 (x^aequiv b (mod p))
((g^c)^aequiv b (mod p))
(g^{ca+k*varphi(p)}equiv b (mod p))

...

(forall kin mathbb{Z},xequiv{c+frac{k*varphi(p)}{gcd(a,varphi(p))}} (mod p)) 为通解

二次剩余就是以上的p为奇质数,a=2的一个特例,但是专门的二次剩余的算法会更快 (O(log p))

还有p不是质数的情况,晕了。

原文地址:https://www.cnblogs.com/purinliang/p/13945178.html