BSGS

BSGS

简介

BSGS(Baby Step, Giant Step)算法,用于解决高次同余方程,即给定整数 \(a,b,p\),其中 \(a \perp p\) (互质),求解最小非负整数 \(x\) 使得 \(a^x \equiv b \pmod p\)

算法流程

\(a^x \equiv b \pmod p\) 化为 \(a^{\lceil \sqrt{p} \rceil \cdot k - s} \equiv b \pmod p\),其中 \(0 \leq k,s \leq \lceil \sqrt{p} \rceil\),因为 \(a^s \perp p\),所以 \(a^{\lceil \sqrt{p} \rceil \cdot k} \equiv a^s \cdot b \pmod p\)。可以思考一下此处构造 \(-s\) 而非构造 \(+s\) 的目的:很显然,是为了方便处理才这么做的。

所以我们就可以使用哈希表预处理 \(a^s \cdot b\),然后再把 \(a^{\lceil \sqrt{p} \rceil \cdot k}\) 丢进去看能否匹配即可。

时间复杂度应该是 \(\mathcal{O(\sqrt{p})}\),如果使用 map 存的话会多一个 \(\log\)

扩展 BSGS

简介

BSGS 显然只能解决 \(a \perp p\) 时的高次同余方程,那么考虑当 \(a\)\(p\) 不互质的时候该如何处理,只能使用扩展 BSGS 来解决。

算法流程

对于 \(a^x \equiv b \pmod p\),考虑将 \(a,p\) 变成互质的。

我们取 \(d = \gcd(a,p)\),由模运算的性质,可得 \(a^{x - 1} \cdot \cfrac{a}{d} \equiv \cfrac{b}{d} \pmod {\cfrac{p}{d}}\),如果 \(b,d\) 不互质,那么可以证明无解;如果此时 \(a,\frac{p}{d}\) 仍然不互质,重复上述过程,记录 \(s\) 为次数。注意,此处我们需要进行优化,当 \(\frac{b}{\prod_{i = 1}^{k} d_i} = \frac{a^k}{\prod_{i = 1}^{k} d_i}\),那么此时我们可以退出计算,并返回此时 \(s\) 的值。

经过上述过程,原式可转换为 \(a^{x - k} \cdot \cfrac{a^k}{\prod_{i = 1}^{k} d_i} \equiv \cfrac{b}{\prod_{i = 1}^{k} d_i} \pmod {\cfrac{p}{d}}\),再转换成为 \(a^{x - k} \equiv \cfrac{b}{a^k} \pmod {\cfrac{p}{d}}\)

然后我们就可以把式子扔进 BSGS 里直接计算了。

$\tt{Link}$
il int qmi(int a,int b,int p) {
	int res = 1;
	while (b) {
		if (b & 1) res = res * a % p;
		a = a * a % p;
		b >>= 1;
	}
	return res;
}

il int exgcd(int a,int b,int &x,int &y) {
	if (!b) {
		x = 1; y = 0;
		return a;
	}
	int d = exgcd(b,a % b,y,x);
	y -= a / b * x;
	return d;
}

il int inv(int x,int p) {
	int invv,y;
	int d = exgcd(x,p,invv,y);
	return (invv % p + p) % p;
}

il int BSGS(int a,int b,int p) {
	st.clear();
	int cnt = (int)ceil(sqrt(p * 1.0));
	b %= p;
	rep(i,1,cnt) (b *= a) %= p,st[b] = i;
	int val = qmi(a,cnt,p);
	a = 1;
	rep(i,1,cnt) {
		(a *= val) %= p;
		if (st.count(a)) return (i * cnt - st[a] + p) % p;
	}
	return -1;
}

il int exBSGS(int a,int b,int p) {
	a %= p; b %= p;
	if (b == 1 || p == 1) return 0;
	int d = __gcd(a,p),s = 0,e = 1;
	while (d > 1) {
		if (b % d) return -1;
		b /= d; p /= d; (e *= (a / d)) %= p; ++ s;
		if (b == e) return s;
		d = __gcd(a,p);
	}
	int res = BSGS(a,b * inv(e,p) % p,p);
	if (res == -1) return -1;
	return res + s;
}
posted @ 2024-01-26 16:17  songszh  阅读(11)  评论(0编辑  收藏  举报