浅谈 BSGS 算法
SClan_Official · · 题解
BSGS(Baby-Step Giant-Step)算法是 Shank 发明的一个用于在
何为离散对数?普通的对数
首先显然如果
考虑一个显然的暴力做法:依次检查。虽然是暴力,但是我们不至于傻到每求一个
BSGS 则利用了幂运算的性质
首先我们暴力求出当
看上去并没有什么作用,但是实际上,如果 set 或者哈希表 unordered_set 或者其它奇奇怪怪的数据结构中)。
进一步地,如果
我们上面都假设
注意本题不仅仅要判断存在性,还要输出解。所以我们不能只保存余数,还要保存下标。
附上丑陋的代码。
#include <cstdio>
#include <unordered_map>
using namespace std;
unordered_map<int, int> um;
long long qpow(int x, int y, int p)
{
if(y == 0) return 1;
if(y == 1) return x;
long long r = qpow(x, y >> 1, p);
r = r * r % p;
if(y & 1) r = r * x % p;
return r;
}
int main()
{
int p, b, n;
scanf("%d%d%d", &p, &b, &n);
int sqrtp = 0;
long long mul = 1;
// 0 ~ sqrtp
for(int i=0;1ll*i*i<=p;i++)
{
sqrtp = i;
if(!um.count(mul = (i == 0 ? 1 : mul * b % p))) um[mul] = i;
if(mul == n)
{
printf("%d\n", i);
return 0;
}
}
sqrtp++; mul = mul * b % p;
long long invmul = qpow(mul, p - 2, p), mulll = 1;
// i*sqrtp ~ (i+1)*sqrtp-1
for(int i=1;1ll*sqrtp*i<=p;i++)
{
if(um.count((mulll = mulll * invmul % p) * n % p))
{
printf("%d\n", um[mulll * n % p] + sqrtp * i);
return 0;
}
}
printf("no solution\n");
return 0;
}
record。
[^1]: 倒是有一种底数确定的