BSGS算法

本文深入讲解BSGS算法,一种高效解决高次同余问题的方法。适用于求解形如ax≡b(modp)的最小非负整数解x,其中p为质数。文章详细阐述了算法原理、步骤及应用实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BSGS \text{BSGS} BSGS 算法,全名 Baby Steps Giant Steps \text{Baby Steps Giant Steps} Baby Steps Giant Steps ,用于解决高次同余问题。


问题

给出 a , b , p a,b,p a,b,p ,请求出最小的非负整数 x x x ,满足 a x ≡ b ( m o d p ) a^x\equiv b\pmod p axb(modp) 。其中 p p p 为质数。


解法

BSGS \text{BSGS} BSGS 板子题。

方法如下:

x = i m − j , m = ⌈ p ⌉ x=im-j,m=\lceil\sqrt{p}\rceil x=imj,m=p ,则 a i m − j ≡ b ( m o d p ) a^{im-j}\equiv b\pmod p aimjb(modp)
移项可得 ( a m ) i ≡ b × a j ( m o d p ) (a^m)^i\equiv b\times a^j \pmod p (am)ib×aj(modp)
首先,从 0 − m 0-m 0m 枚举 j j j ,将得到的 b × a j b\times a^j b×aj 的值存入 hash \text{hash} hash 表;
然后,从 1 − m 1-m 1m 枚举 i i i ,计算 ( a m ) i (a^m)^i (am)i ,查表,如果有值与它相等,那么这时找到的 i m − j im-j imj 一定是最小值。


备注

  1. 为什么令 m = ⌈ p ⌉ m=\lceil\sqrt p \rceil m=p
    ∵ a φ ( p ) ≡ 1 ( m o d p ) ∵a^{φ(p)}\equiv 1\pmod p aφ(p)1(modp)
    ∴ 方 程 的 最 小 非 负 整 数 解 x ≤ φ ( p ) ∴方程的最小非负整数解x\leq φ(p) xφ(p)
    ∵ φ ( p ) < p ∵φ(p)<p φ(p)<p
    ∴ x < p ∴x<p x<p
    所以枚举 x x x 时上界设定为 p p p 即可
    按照 BSGS \text{BSGS} BSGS 算法的思想,显然此算法在 m = ⌈ p ⌉ m=\lceil \sqrt p \rceil m=p 时效率最高。
    但是欧拉定理的使用是有前提限制的: a , p a,p a,p 要互质。如果不满足这个条件,上面的证明也就是无稽之谈。
    也就是说, BSGS \text{BSGS} BSGS 算法只能在 gcd ⁡ ( a , p ) = 1 \gcd(a,p)=1 gcd(a,p)=1 时使用。

  2. i , j i,j i,j 的枚举方式?
    首先我们要明确一点:枚举 j j j b × a j b\times a^j b×aj 的值可能重复,这时我们要用当前较大的值取代之前的较小值。
    原因很简单: j j j 越大, i m − j im-j imj 越小嘛qwq
    在我们枚举到最小的满足题意的 i i i 时,易知这时的 i m − j im-j imj 一定是答案。
    为了保证 x = i m − j > 0 x=im-j>0 x=imj>0 ,显然 i i i 应该从 1 1 1 开始枚举。

  3. 时间复杂度
    看起来应该是 O ( p ) \mathcal O(\sqrt p) O(p ) 的?
    不过如果你使用 map 作为哈希表,时间复杂度会乘上一个 log ⁡ \log log ,因为 map 是红黑树实现的


实现

UPD on 2019/11/14 感觉还是要放个题233 \text{UPD on 2019/11/14 感觉还是要放个题233} UPD on 2019/11/14 感觉还是要放个题233

方便起见这里直接给出一道模板题
P 3846   [ T J O I 2007 ] 可 爱 的 质 数 \rm P3846\ [TJOI2007]可爱的质数 P3846 [TJOI2007]
题意很明确,就是道板子题,下面就直接放代码了

#include<cstdio>
#include<cmath>
#define rep(i,l) for (int i=l; i<=m; ++i)
const int P=10003; int cnt,p,a,b,m,s,t,res=1,last[P];
struct node { int x,i,pre; }E[1<<16];
void add(int i,int x) { E[++cnt]=(node){i,x,last[i%P]}; last[i%P]=cnt; }
int find(int i) { //查哈希表
	for (int j=last[i%P]; j; j=E[j].pre) if (E[j].x==i) return E[j].i;
	return -1; //-1表示没有找到
}
int main() {
	scanf("%d%d%d",&p,&a,&b); m=ceil(sqrt(p)); //ceil向上取整
	s=b; rep(j,0) add(s,j),s=1ll*s*a%p; s=1; rep(j,1) s=1ll*s*a%p;
	rep(i,1) if (~(t=find(res=1ll*res*s%p))) return printf("%d\n",i*m-t),0;
	puts("no solution"); return 0;
}

毒瘤码风不要在意qwq
这里的哈希表是哈希+拉链法直接搞的,比map应该要快一些


下一篇: EXBSGS \text{EXBSGS} EXBSGS

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值