【数学】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不是质数的情况,晕了。