大步小步算法

考虑这样一个问题:

题目 给定正整数 (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;
}
原文地址:https://www.cnblogs.com/whx1003/p/12602150.html