BSGS学习笔记
大步小步算法
BSGS(baby-step giant-step),即大步小步算法。常用于求解离散对数问题。该算法可以在 \(O(\sqrt{p})\) 的时间内求解
\[a^x \equiv b \pmod p
\]
其中,\(a \perp p\)。方程的解满足 \(0 \leq x <p\)。
算法描述
令 \(x=A\left \lceil \sqrt{p} \right \rceil -B\),其中 $0 \leq A,B \leq \left \lceil \sqrt{p} \right \rceil $,则有 \(a^{A\left \lceil \sqrt{p} \right \rceil -B} \equiv b \pmod p\)。变换一下,得到 \(a^{A\left \lceil \sqrt{p} \right \rceil }=ba^B \pmod p\)。
由于 \(a,b\) 已知,所以可以先算出等式右边的 \(ba^B\) 的所有取值,由于 $B \leq \left \lceil \sqrt{p} \right \rceil $,所以一共有 \(O(\sqrt{p})\) 个取值,用 hash 或 map 存下来,然后逐一计算 \(a^{A\left \lceil \sqrt{p} \right \rceil }\),枚举 \(A\),查询是否有与之对应的 \(ba^B\)。总的时间复杂度就为 \(O(\sqrt{p})\),如果用 \(map\) 则多一个 \(\log\)。
code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<unordered_map>
using namespace std;
int a,p,b;
int BSGS(int a,int p,int b)
{
if(1%p==b%p) return 0;
unordered_map<int,int>pos;
int k=sqrt(p)+1,tmp=1;
for(int i=0,j=b;i<k;i++){pos[j]=i;j=1ll*j*a%p;}
for(int i=1;i<=k;i++) tmp=1ll*tmp*a%p;
for(int i=1,j=tmp%p;i<=k;i++)
{
if(pos.count(j)) return 1ll*i*k-pos[j];
j=1ll*j*tmp%p;
}
return -1;
}
int main()
{
scanf("%d%d%d",&p,&a,&b);
int res=BSGS(a,p,b);if(res==-1) puts("no solution");else printf("%d\n",res);
return 0;
}