找到最小的 使得 。
我们不妨想象一个巨大的操场,其上等距排列着从 到 的 个位置,起始时我们站在位置 (单位元)。 从 开始,每增加 ,我们就从现在的位置 前进一次 到 ;该过程将始终进行,直到在前进 次后,我们停在了位置 上。最暴力的方法即为枚举,但对于大多数题目而言, 的值通常很大,在大的操场上枚举是较为困难的。
BSGS 算法可以解决这样的问题。假如现在我们向操场派出两个人,Baby-Step 和 Giant-Step,让他们帮助我们完成在操场上行走。值得注意的是,两个人的行走策略有所差异:Baby-Step 每次行动仅前进一次,但 Giant-Step 每次行动可前进多次。 我们让 Baby-Step 和 Giant-Step 分别从终点和起点出发,他们在操场上各自前进;当他们相遇的时候,我们取 Giant-Step 从起点到相遇点的前进次数和 Baby-Step 从终点到相遇点的前进次数,只需对两者作差,即得到我们从起点到终点需要前进的次数,并可以以此推导出答案。
这里,我们将总前进次数 分为
其中, 表示 Giant-Step 的行动次数, 表示 Giant-Step 的一次行动前进多少次, 表示 Baby-Step 的前进次数。通常取 为 。我们将上述式子先代入原方程中,有
在同余式两边同乘以 ,得
这个式子是算法的核心。同余式左侧 显示了 Giant-Step 的行动,右侧 显示了 Baby-Step 的行动。
在继续之前,我们需要说明一个前提:以下默认 。在多数题目中 为素数且 不是 的倍数,因此这个条件自然成立。该条件保证了 在模 下可逆,从而可以从右侧等式反推出原来的 。
另外,如果 ,显然 就是最小解,因此实现时应先特判并直接返回 。
下面描述具体过程。
对于 Baby-Step,起初站在终点 上,并使用一张哈希表记录着其前进的全过程:前进 次时,记录「前进 次到达了 」;前进 次时,记录「前进 次到达了 」……Baby-Step 一直如此前进直到 次,将这 对「前进次数—到达位置」的关系全部记录在了一张哈希表里。现在,这个哈希表则类似于一张地图,它记录了从终点 出发,前进不到 次,即 到 次能到达的所有位置。若同一个位置被多次到达,实现时应保留更大的 ,以保证最终得到的 尽可能小。
下面,我们让 Giant-Step 出发,站在起点 上。行动 次(前进 次)时,Giant-Step 对照哈希表以检验自己现在所处的位置 是否位于哈希表内:如果有,则停止;如果否,则继续行动 次。Giant-Step 将一直行动,直到第 次行动时,其处于的位置 恰好位于哈希表内。这样,我们便知道了:Giant-Step 从起点 出发,行动 次(前进 次)后到达了相遇点;Baby-Step 从终点 出发,前进 次后也到达了相遇点。因此,若我们从起点出发,只需前进
次即可到达终点。
由于 ,任意可能的 都可以写成 的形式,其中 ,。因此 Giant-Step 至多行动 次,Baby-Step 也至多记录 条哈希表,所以算法总复杂度为 的时间和 的空间。在 MoeCTF 2025 的这道 ezBSGS 题目 中, 的值大约为 ,但 的值仅为 ,可以认为 BSGS 算法是容易计算的。