BSGS
大步小步算法
基础篇
大步小步算法英文名: baby-step gaint-step (BSGS) .
该算法可以在 用于求解
其中 是个质数的方程的解 满足 .
令 ,其中 ,
则有 ,稍加变换,则有 .
我们已知的是 ,所以我们可以先算出等式右边的 的所有取值,枚举 ,用 hash/map 存下来,然后逐一计算 ,枚举 ,寻找是否有与之相等的 ,从而我们可以得到所有的 , .
注意到 均小于 ,所以时间复杂度为 ,用 map 的话会多一个 .
BZOJ-2480是一道模板题(可能是权限题),BZOJ-3122是一道略加变化的题,代码可以在Steaunk 的博客中看到。
略微进阶篇
求解
其中 是个质数。
该模型可以通过一系列的转化为成 基础篇 中的模型,你可能需要一些关于原根的概念。
原根的定义 为:对于任意数 ,满足 ,且 为最小的 正整数 满足 ,则称 是 模 意义下的次数,若 ,则称 是 的原根。
首先根据 原根存在的条件 ,对与所有的素数 和正整数 ,当且仅当 时有原根,
那么由于式子中的模数 ,那么一定存在一个 满足 是 的原根,即对于任意的数 在模 意义下一定有且仅有一个数 ,满足 ,且 .
所以我们令 , 是 的原根(我们一定可以找到这个 和 ),则为求 的关于 的解集,稍加变换,则有 ,于是就转换成了我们熟知的 BSGS 的基本模型了,即可在 解决。
那么关键的问题就在于如何找到这个 了?
关于对于存在原根的数 有这样的 性质 :若 是 模 的次数(这里蕴含了 ),那么对于任意的数 ,满足 ,则 .
PROOF
记 , .
.
, 是 模 的次数,即 是最小的 正整数 满足 .
.
即 ,
Q.E.D.
由此当 是质数的时候还有这样的推论:如果不存在小于 且整除 正整数 , 满足 ,那么又根据 费马小定理 ,有 ,所以 是 模 的次数,即 是 的原根。
于是可以得到一种基于 原根分布 的算法来找原根,首先把 的因数全部求出来,然后从 到 枚举,判断是否为原根,如果对于数 , , 是 的因数,则 一定不是 的原根。
看上去复杂度好像很爆炸(可能确实是爆炸的,但一般情况下,最小的原根不会很大)。
基于一个 假设 ,原联系根是 均匀分布 的,我们 伪证明 一下总复杂度:原根数量定理:数 要么没有原根,要么有 个原根。
由于 是质数,所以 有 个原根,所以大概最小的原根为 ,由于求每一个数时要枚举一遍 所有的因数 来判断其是否为原根,最后再算上 BSGS 的复杂度 ,则复杂度约为 .
BZOJ-1319是一道模板题,代码可以在Steaunk 的博客中看到。
扩展篇
上文提到的情况是 为素数的情况,如果 不是素数呢?
这就需要用到扩展 BSGS 算法,不要求 为素数!
扩展 BSGS 用到了同余的一条性质:
令 ; 则 等价于 所以我们要先消除因子:
| d = 1, num = 0, t = 0;
for (int t = gcd(a, c); t != 1; t = gcd(a, c)) {
if (b % t) {
\\无解
}
b /= t;
c /= t;
d *= a / t;
num++;
}
|
消除完后,就变成了 ,令 ,后面的做法就和普通 BSGS 一样了。
注意,因为 ,所以 ,但不排除解小于等于 的情况,所以在消因子之前做一下 枚举,直接验证 ,这样就能避免这种情况。
build本页面最近更新:,更新历史
edit发现错误?想一起完善? 在 GitHub 上编辑此页!
people本页面贡献者:
copyright本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用