BSGS、exBSGS

BSGS

  \(\text{BSGS}\)\(\text{Baby Step Giant Step}\))是用来解决\(a^x \equiv b \pmod p\)的问题。

(a,p)=1

  令\(m=\lceil \sqrt{p} \rceil\),则\(x\)可以表示成\(mq+r\),其中\(0 \leq q \leq m\)\(0 \leq r < m\)

  那么\(a^x\equiv b \pmod p\)可以写成\(a^{mq+r} \equiv b \pmod p\)

  移项得:\(a^{mq} \equiv ba^{-r} \pmod p\)

  现在问题变成了:找出一组\(q\)\(r\),使得上式成立,我们枚举\(q\),将左边得到的式子的所有种取值哈希起来,然后再枚举\(r\),判断右边的取值是否在左边的取值中出现,如果出现就找到了解。

  枚举部分的复杂度\(\text{O}(\sqrt p)\),求逆元的复杂度为\(\text{O}(\log p)\),所以总复杂度为\(\text{O}(\sqrt p + \log p)\)

  如果你不愿意求逆也可以,只要设\(x=mq-r\),然后\(0 < q \leq m\)\(0 \leq r < m\),然后移项过程中\(-r\)变成\(+r\),于是就不用逆元了。

unordered_map<int, int> Hash;
int BSGS(int a, int b) { // a^x=b(P)
	if (!a) return b ? -1 : 1; // 0^x=0的特判
	Hash.clear(); // 清空
	int m = (int)ceil(sqrt(P+0.5)), am = qpow(a, m), t = 1; // 求出m,am
	for (int i = 1; i <= m; i++, t = 1ll*t*am%P) if (!Hash.count(t)) Hash[t] = i; // 将a^mi插入(不可重复插入,否则大的会覆盖小的)
	int ans = -1; t = b;
	rep0(i, m) {
		unordered_map<int, int>::iterator it = Hash.find(t); // 查看是否存在
		if (it != Hash.end()) {
			int x = it->second * m - i;
			if (ans == -1 || x < ans) ans = x;
		}
		t = 1ll*t*a%P;
	}
	return ans; // -1表示无解
}

(a,p)≠1

  这种情况下,\(a\)的逆元不存在,所以我们要约分两边使得\(a\)的逆元出现。

  对于\(a^x \equiv b \pmod p\),提出一个\(d=(a,p)\)并约分得到\(a^{x-1}\frac{a}{d} \equiv \frac{b}{d} \pmod {\frac{p}{d}}\)。当然要有\(d \mid b\),否则无解。

  继续,如果\(d'=(a,\frac{p}{d}) \neq 1\),再拿出一个\(a\)提取因子,得到\(a^{x-2}\frac{a}{d}\frac{a}{d'} \equiv \frac{b}{dd'} \pmod {\frac{p}{dd'}}\)

  以此类推,直到其互质,此时有\(a^{x-t}\frac{a^t}{\prod d} \equiv \frac{b}{\prod d} \pmod {\frac{p}{\prod d}}\)

  显然此时\(\frac{a^t}{\prod d}\)存在逆元,于是可以移过去得到\(a^{x-t} \equiv \frac{b}{\prod d}\frac{a^{-t}}{\prod d} \pmod {\frac{p}{\prod d}}\),然后就成了上面的问题。

  这里约分时由于约分和求公约数,多了一个\(\text{O}(\log^2 p)\)的复杂度,其他不变。

int exBSGS(int a, int b, int P) {
	if (!a) return b ? -1 : 1; // 直接特判
	int t = 0, d, l = 1;
	while (d = gcd(a, P), d > 1) {
		if (b % d) return -1; // 不能整除一定无解
		P /= d, b /= d, l = 1ll*l*(a/d)%P, t++; // 约分,记录指数,记录系数
	}
	a %= P, b = 1ll*b*inv(l, P)%P; // 维护新的a,b
	int ans = BSGS(a, b, P); // 求解
	return ~ans ? ans+t : -1; // 补上t或者无解
}
posted @ 2020-05-07 19:56  AC-Evil  阅读(177)  评论(0编辑  收藏  举报