📚【模板】BSGS
给你\(a,b,p\in \mathbb{N}_+\),请解出方程\(a^x\equiv b\pmod p\)的最小解\(x\in\mathbb{N}_+\)。
首先设:
\[t = \left\lfloor\sqrt p\right\rfloor
\]
\[x = i\times t-j
\]
则有:
\[a^{i\times t-j}\equiv b\pmod p
\]
于是有:
\[\left(a^t\right)^i\equiv b\times a^j\pmod p
\]
现在我们枚举\(j\),建立\(b\times a^j\bmod p\to j\)的映射关系。
然后枚举\(i\),查看映射表中是否有与\(\left(a^t\right)^i\bmod p\)相同的值。
得到\(i,j\),答案即为\(i\times t-j\)。
#include <stdio.h>
#include <map>
#define ull unsigned long long
#define ll long long
ll light_multi(ll _a,ll _b,ll _p) {
_a %= _p, _b %= _p;
ull _c = (long double)_a*_b/_p;
ull _x = _a*_b, _y = _c*_p;
ll _res = (ll)(_x%_p)-(ll)(_y%_p);
if(_res < 0) _res += _p;
return _res;
}
ll defended_pow(ll _a,ll _n,ll _p) {
ll _res = 1;
while(_n) {
if(_n&1) _res = light_multi(_res,_a,_p);
_a = light_multi(_a,_a,_p);
_n >>= 1;
}
return _res;
}
float InvSqrt(float x) {
float xhalf = 0.5f*x;
int i = *(int*)&x;
i = 0x5f375a86-(i>>1);
x = *(float*)&i;
x = x*(1.5f-xhalf*x*x);
x = x*(1.5f-xhalf*x*x);
x = x*(1.5f-xhalf*x*x);
return x;
}
std :: map<ll,ll> hash;
ll BSGS(ll a,ll b,ll p) {
b %= p;
ll t = (ll)(1.0/InvSqrt(p))+1;
for(ll i = 0;i < t;++i)
hash[b*defended_pow(a,i,p)%p] = i;
a = defended_pow(a,t,p);//ATP www ;
if(!a) return b == 0 ? 1 : -1;
for(ll i = 1;i <= t;++i) {
ll tmp = defended_pow(a,i,p);
int j = (hash.find(tmp) == hash.end()) ? -1 : hash[tmp];
if(j >= 0&&i*t-j >= 0)
return i*t-j;
}
return -1;
}
ll a, b, p;
signed main() {
scanf("%lld %lld %lld",&p,&a,&b);
ll ans = BSGS(a,b,p);
if(ans == -1)
printf("no solution");
else
printf("%lld",ans);
}
\(\text{luogu P3306 [SDOI2013] 随机数生成器}\)