考虑这样一个问题:
题目 给定正整数 (a,b,p) 求满足 (a^xequiv bpmod p) 的所有正整数解 (x),保证 (p) 是素数。
分析 首先由费马小定理,(a^{p-1}equiv 1pmod p),也就是说暴力算法只需要枚举到 (p-1) 即可,我们考虑优化。
我们考虑只暴力求解 (a^xmod p) 的前 (m) 个值,也即 (a^1mod p,a^2mod p,cdots,a^mmod p)。那么现在来考虑后面的数,将其 (m) 个一组分组(就是 (m+1,m+2,cdots,2m) 一组,(2m+1,2m+2,cdots,3m) 一组)。对于每一组这样考虑:如果
[a^{km+t}equiv bpmod p
]
这等价于
[a^tequiv bcdot (a^{km})^{-1}equiv bcdot (a^{-m})^kpmod p
]
也就是说,我们在枚举每一个 (k) 的时候可以直接将 (bcdot (a^{-m})^k mod p) 与每一个 (a^i) 对比,看是否有相同的,这可以用 (map) 实现。
这个算法被称为大步小步(Baby Step Giant Step, BSGS, 拔山盖世)算法。它的复杂度为 (O((m+frac n m)log m)),当 (m=sqrt{n}) 时最优,为 (O(sqrt{n}log n))
ll BSGS(ll a, ll b, ll mod)
{
map<ll, ll> Map;
ll m = sqrt(mod + 0.5), tmp = 1;
for(int i = 0; i < m; ++i) {
if(!Map.count(tmp)) Map[tmp] = i;
tmp = tmp * a % mod;
}
ll inv = qPow(tmp, mod - 2, mod);
for(int i = 0; i < m; ++i) {
if(Map.count(b)) return i * m + Map[b];
b = b * inv % mod;
}
return -1;
}