【数学】BSGS算法

BSGS算法

求解 \(a^x\equiv 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 b\cdot a^{x_2} (\mod m)\)

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

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

扩展BSGS算法

求解 \(a^x\equiv 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;
    M.reserve (2 * 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^a\equiv b (\mod p)\)

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

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

方法一:

原式变为 \((g^c)^a\equiv b (\mod p)\)

\((g^a)^c\equiv b (\mod p)\)

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

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

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

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

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

找到所有解:

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

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

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

...

\(\forall k\in \mathbb{Z},x\equiv{c+\frac{k*\varphi(p)}{gcd(a,\varphi(p))}} (\mod p)\) 为通解

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

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

posted @ 2020-11-08 18:21  purinliang  阅读(102)  评论(0编辑  收藏  举报