【数学】BSGS 算法

时间:2024-03-29 11:40:52

功能:

求解 a x ≡ b ( m o d p ) a^x\equiv b \pmod{p} axb(modp),其中 a a a p p p 互质。

算法流程:

由欧拉定理得, a t ≡ a t     m o d     φ ( p ) ( m o d p ) a^t\equiv a^{t\ \bmod\ \varphi (p)}\pmod{p} atat mod φ(p)(modp)

所以,最小的整数 t t t 使得 a t ≡ b ( m o d p ) a^t\equiv b\pmod{p} atb(modp),一定是小于 φ ( p ) \varphi (p) φ(p) 的,那么考虑枚举 1 ∼ φ ( p ) 1\sim \varphi(p) 1φ(p),不过通常为了方便,直接枚举 1 ∼ p 1\sim p 1p 即可(因为求 φ ( p ) \varphi(p) φ(p) 比较麻烦)。

1 ∼ p 1\sim p 1p 分成 p \sqrt p p 段,每一段的长度 k = p + 1 k=\sqrt p+1 k=p +1,这时候 t = k x − y t=kx-y t=kxy,其中 x ∈ [ 1 , k ] , y ∈ [ 0 , k ) x\in [1,k],y\in [0,k) x[1,k],y[0,k)

此时问题转化为了求 a k x − y ≡ b ( m o d p ) a^{kx-y}\equiv b\pmod{p} akxyb(modp),即 a k x ≡ a y b ( m o d p ) a^{kx}\equiv a^yb \pmod{p} akxayb(modp)

那么,枚举 x x x 后就是看最大的合法的 y y y 是多少?这个可以通过哈希来解决,具体来说就是提前将 a y b   m o d   p a^yb\bmod p aybmodp 存入哈希表中,其中 y ∈ [ 0 , k ) y\in [0,k) y[0,k),如果有相同的值选择较大的一个。

代码:

#include <bits/stdc++.h>
#define int long long

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

int BSGS(int a, int b, int p) {
	if (1 % p == b % p) return 0;
	unordered_map<int, int> hash;
	int k = sqrt(p) + 1;
	for (int i = 0, j = b % p; i < k; i ++)
		hash[j] = i, j = j * a % p;
	int ak = 1;
	for (int i = 1; i <= k; i ++) ak = ak * a % p;
	for (int i = 1, j = ak; i <= k; i ++) {
		if (hash.count(j)) return k * i - hash[j];
		j = j * ak % p;
	}
	return -1;
}

signed main() {
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(0);

	int a, b, p;
	while (cin >> a >> p >> b, a || p || b) {
		int res = BSGS(a, b, p);
		if (res == -1) cout << "No Solution" << endl;
		else cout << res << endl;
	}

	return 0;
}