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;
}
posted @ 2023-03-17 08:34  曙诚  阅读(29)  评论(0)    收藏  举报