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;
}

浙公网安备 33010602011771号