Shank's Baby-Step-Giant_Step Algorithm(BSGS)

解模方程 (\(n\) 为素数)

\[a^x \equiv b (\bmod n) \]

因为欧拉定理 \(a^{\phi(n)} \equiv 1 (\bmod n)\) (\(n\) 为素数)。

\[ 0\le x \le n - 1 \]

\(m = \sqrt{n+0.5}\)

暴力计算 \(a^i \bmod n (0 \le i \le m - 1)\) 的值,并放在 \(map\) 中。

对于\(a^i \bmod n (0 \le i \le n - 1)\),可以写为 \(a^{im + j} \bmod n(0 \le i , j \le m - 1)\)

\(i,j\) 取最大值时,有 \(m(m - 1) + (m-1) = (m + 1)(m - 1) = m^2 - 1 = n - 1\),恰好取到了 \(n - 1\)

\[ a^x \equiv a^{im + j} \equiv b (\bmod n) (0 \le i \le n - 1) \]

\[ a^j \equiv b \times a^{-im} (\bmod n) (0 \le i \le n - 1) \]

暴力枚举 \(i\), 并计算 \(b\times a^{-im}\) 的值。

\(map\) 中检查其值是否存在,若有则找到了最优解 \(x\), 否则继续枚举 \(i\)

\(0 \le i \le n - 1\) 均没有找到解时,说明无解。

#include <iostream>
#include <map>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
ll ksm(ll x, ll y, ll mod){
	ll rhs = 1;
	while(y){
		if(y&1) rhs = (rhs * x) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return rhs;
}
void exgcd(ll a, ll b, ll &d, ll &x, ll &y){
	if(b == 0){d = a;x = 1;y = 0;return;}
	exgcd(b, a % b, d, y, x);
	y -= x * (a/b);
}
ll inv(ll a, ll mod){
	ll x, y, d;
	exgcd(a, mod, d, x, y);
	return (x + mod) % mod;
}
map<ll, ll> mp;
ll BSGS(ll a, ll b, ll mod){
	ll m, invam = 1, c = 1;
	m = (ll) sqrt(mod + 0.5);
	invam = inv(ksm(a, m, mod), mod);
	mp[1] = 0;
	for(ll i = 1; i < m; i ++){
		c = (c * a) % mod;
		if(!mp.count(c)) mp[c] = i;
	}
	for(ll i = 0; i < m; i ++){
		if(mp.count(b)) return i * m + mp[b];
		b = (b * invam) % mod;
	}
	return -1;
}
int main(){
	ll p, b, n;
	cin >> p >> b >> n;
	ll Ans = BSGS(b, n, p);
	if(Ans == -1)puts("no solution");
	else printf("%lld\n", Ans);
	return 0;
}
posted @ 2023-01-04 10:03  fzrcy  阅读(37)  评论(0)    收藏  举报