BSGS算法及其扩展算法

BSGS算法

所谓 Baby Step, Giant Step 算法,也就是暴力算法的优化

用于求出已知 \(a, b, p\), 且 \(p\) 为质数 时 \(a^x \equiv b \pmod p\) 的一个最小正整数解 \(x\)

下文中 \(a \perp p\) 指的是 \(a, p\) 互质

有两种情况:

  • \(a, p\) 不互质,又由于 \(p\) 是质数,意味着 \(a\) 是 \(p\) 的倍数,所以 \(b\) 如果不为 \(0\) ,那么一定无解

  • 两者互质……即 \(a \perp p\) :

考虑到 \(a \perp p\) 意味着 \(a\) 在 \(p\) 的完全剩余系中,也就是说 \(f(x) = a^x \pmod p\) 是一个周期为 |<a>| (……就是 \(a\) 在模 \(p\) 意义下的生成子群的大小) 的周期函数

实际上我们不会算出其周期的具体大小,我们只需要利用 |<a>| 恒 \(\le p\) 就行了

那么我们只需要枚举 \(x \in [0, p)\) 依次验证就可以求解了

但是暴力枚举没有那么优秀,对于出题人的数据可能过不了

所以我们就可以采用把毒瘤出题人吊起来打的方法BSGS算法进行优化


BSGS算法采用分块的思想 (分块?块大小就 \(\sqrt p\) 不就就行了吗,有什么好疑惑的?

假设块大小为 \(t\)

先参入 \(t\) 改写一下式子 \(a^x \equiv b \pmod p\)

得到 \(a^{it-j} \equiv b \pmod p\)

由于 \(a \perp p\) ,上述式子等价于 \(a^{it} \equiv (a^t)^i \equiv b a^j \pmod p\)

那么我们先预处理右式,枚举 \(j \in [0, t)\) 把 \(ba^j \mod p\) 插入到一个Hash表中

也就是说 \(HashMap: \quad ba^j\ mod\ p \Rightarrow j\)

那么枚举 \(i \in [0, \lceil \frac pt \rceil]\) 计算出 \(a^{it} \mod p\) ,查找是否有对应的 \(j\),更新答案即可

时间复杂度为 \(O(t + \lceil \frac pt \rceil)\)

为了进一步优化时间复杂度,已知均值不等式 \(a + b \ge 2\sqrt{ab}\),当且仅当 \(a=b\) 时等号成立,所以我们令 \(t = \lceil \sqrt p \rceil\),那么时间复杂度就简化为了 \(O(\sqrt p)\)

常数为 \(2\) 可能还需要带一个 \(log\) ? QwQ

参考代码如下:仅供参考

template<typename data>
data BSGS(data a, data b, data p) {
b %= p;
static std::map<data, data> hash; hash.clear();
data t = std::ceil(std::sqrt(p)), v(1), j(0);
for (; j < t; ++j) {
// 此时 v = a^j % p
hash[v * b % p] = j;
v = v * a % p;
} // 把 a 预处理成 a^t, 这样 (a^t)^i 就可以更快的算出了
a = qpow(a, t, p), v = 1;
// 如果此时 a 已经为 0 了,由于 t < p, p为质数所以 p|a (a为p的倍数)
// 那么此时,如果 b 不为 0 则一定无解
if (a == 0) return b == 0 ? 1 : -1; for (data s(0); s <= t; ++s) {
// 此时 v = (a^t)^s
j = hash.find(v) == hash.end() ? -1 : hash[v];
if (~j && s * t >= j) return s * t - j;
v = v * a % p;
}
return -1;
}

扩展BSGS算法 (exBSGS)

其实问题一摸一样,只是 \(p\) 不为质数了,也就是说其中 \(a, p\) 不一定互质

那么我们需要想办法使之变得互质,然后通过普通的 BSGS 算法求解

具体的,令 \(d_1 = gcd(a, p)\),如果 \(d_1 \nmid b\) 则原方程无解

这个我们可以将同余式转换:\(s a^x + tp = b\)

左式再转化为 \(d_1 (s a^{x-1} \frac a{d_1} + t \frac p {d_1}) = b\)

也就是说,如果 \(d_1 \nmid b\) ,那么一定无整数解

那么上述式子就可以转化为 \(sa^{x-1} \frac a{d_1} + t \frac p {d_1} = \frac b {d_1}\)

再换成同余式子,就变为了 \(\frac a {d_1}\cdot a^{x-1} \equiv \frac b {d_1} \pmod {\frac p {d_1}}\)

如果此时 \(a\) 与 \(\frac p {d_1}\) 任然不互质,那么继续上述转化,令\(d_2 = gcd(a, \frac p {d_1})\)

则 \(\frac a {d_1 d_2} \cdot a^{x-2} \equiv \frac b {d_1 d_2} \pmod {\frac p {d_1 d_2}}\)

同理不断处理,直到 \(a \perp \frac p {d_1 d_2 \dots d_k}\)

我们记 \(D = \prod_{i = 1}^k d_i\)

那么最终的方程就是 \(\frac {a^k} {D} \cdot a^{x-k} \equiv \frac bD \pmod {\frac pD}\)

这样,我们把 \(\frac {a^k}D\) 通过逆元丢到方程右边,就成为了一个普通的 BSGS 问题了

注意一个细节,不排除解小于等于 \(k\) 的情况,所以在消去 \(d_i\) 的时候还要判断一下 \(a^i \equiv b \pmod p\) 是否可行

还有一些细节问题我会放在代码之后解释

参考代码:仅供参考

// inv(i) i \equiv 1 mod p
// i * inv(i) + kp = 1 (kown i, p, 1)
template<typename T>
T inv(T i, T p) {
T iv, k;
exgcd(i, p, &iv, &k);
iv %= p;
// 注意点4
return iv < 0 ? iv + p : iv;
} data exBSGS(data a, data b, data p) {
// 注意点 1
b %= p;
// 注意点 2
if (b == 1 || p == 1) return 0;
data d, ak(1), k(0);
while ((d = gcd(a, p)) != 1) {
if (b % d) return -1;
++k, p /= d, b /= d;
ak = a / d * ak % p;
// 注意点 3
if (ak == b) return k;
} // 注意点 4
b = b * inv(ak, p) % p;
data res = BSGS(a, b, p);
// 注意点 5
if (~res) return res + k;
return -1;
}

注意点1:为什么需要一次 b %= p

考虑这样一组数据 a = 10, b = 110, p = 100

其实这个地方也可以加一句 a %= p,可以减少部分运算,也不会影响正确性,反正都是乘法,模意义下人人平等

注意点2:这里的特判是什么意思

如果p为1,相当于同余式恒成立,所以直接返回最小答案即可

如果b为1,考虑到 \(\forall a \ne 0, a^0 = 1\),所以直接返回最小答案即可

注意点3:这就是上文中答案小于 \(k\) 情况的特判

注意点4

由于是在模 \(\frac pD\) 意义下,所以需要通过逆元的方式调整

但是考虑到两者不知道是否互质,所以通过扩展欧几里得算法就行了

扩展欧几里得算法可以参考:算法学习笔记(1): 欧几里得算法及其扩展

注意点5

由于我们在求 \(D\) 的时候消耗了 \(k\) 个\(a\),所以需要加上 \(k\) 才是正确答案

算法学习笔记(10): BSGS算法及其扩展算法的更多相关文章

  1. 算法学习笔记(8.1): 网络最大流算法 EK, Dinic, ISAP

    网络最大流 目录 网络最大流 EK 增广路算法 Dinic ISAP 作者有话说 前置知识以及更多芝士参考下述链接 网络流合集链接:网络流 最大流,值得是在不超过管道(边)容量的情况下从源点到汇点最多 ...

  2. 算法学习笔记(9): 中国剩余定理(CRT)以及其扩展(EXCRT)

    扩展中国剩余定理 讲解扩展之前,我们先叙述一下普通的中国剩余定理 中国剩余定理 中国剩余定理通过一种非常精巧的构造求出了一个可行解 但是毕竟是构造,所以相对较复杂 \[\begin{cases} x ...

  3. Johnson 全源最短路径算法学习笔记

    Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...

  4. 算法学习笔记(3): 倍增与ST算法

    倍增 目录 倍增 查找 洛谷P2249 重点 变式练习 快速幂 ST表 扩展 - 运算 扩展 - 区间 变式答案 倍增,字面意思即"成倍增长" 他与二分十分类似,都是基于" ...

  5. Miller-Rabin 与 Pollard-Rho 算法学习笔记

    前言 Miller-Rabin 算法用于判断一个数 \(p\) 是否是质数,若选定 \(w\) 个数进行判断,那么正确率约是 \(1-\frac{1}{4^w}\) ,时间复杂度为 \(O(\log ...

  6. C / C++算法学习笔记(8)-SHELL排序

    原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...

  7. Manacher算法学习笔记 | LeetCode#5

    Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...

  8. Effective STL 学习笔记 Item 34: 了解哪些算法希望输入有序数据

    Effective STL 学习笔记 Item 34: 了解哪些算法希望输入有序数据 */--> div.org-src-container { font-size: 85%; font-fam ...

  9. 【HLSL学习笔记】WPF Shader Effect Library算法解读之[DirectionalBlur]

    原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[DirectionalBlur] 方位模糊是一个按照指定角度循环位移并叠加纹理,最后平均颜色值并输出的一种特效. ...

  10. 【HLSL学习笔记】WPF Shader Effect Library算法解读之[Embossed]

    原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[Embossed] Embossed(浮雕效果)          浮雕效果主要有两个参数:Amount和Wid ...

随机推荐

  1. MySQL—一条查询SQL语句的完整执行流程

    MySQL-一条查询SQL语句的完整执行流程 表结构和数据如下: 我们分析的sql语句如下: select tb_id,tb_name,tb_address from tb_user where tb ...

  2. 力扣1662(java&python)-检查两个字符串数组是否相等(简单)

    题目: 给你两个字符串数组 word1 和 word2 .如果两个数组表示的字符串相同,返回 true :否则,返回 false . 数组表示的字符串 是由数组中的所有元素 按顺序 连接形成的字符串. ...

  3. EMAS移动测试-远程真机篇

    简介: 导读:本文将介绍申请远程真机以及在远程真机上执行测试任务的详细操作,包括申请远程真机.安装应用.扫码.定位.性能测试等. 一.移动测试概览 移动测试服务(Mobile Testing)是为企业 ...

  4. 阿里云全站加速DCDN重磅发布!打造新一代加速引擎

    简介: 新一代的加速引擎DCDN,安全.高效.可计算 在数字化转型变革逐步深入的当下,安全高效成为企业上云.全球化部署的关键需求. 随着应用场景复杂度不断提升.业务需求差异化发展,为了给企业提供更完善 ...

  5. Dataphin核心功能(四):安全——基于数据权限分类分级和敏感数据保护,保障企业数据安全

    简介:<数据安全法>的发布,对企业的数据安全使用和管理提出了更高的要求.Dataphin提供基于数据分级分类和数据脱敏的敏感数据识别和保护能力,助力企业建立合规的数据安全体系,保障企业数据 ...

  6. MaxCompute跨境访问加速解决方案

    简介: MaxCompute联合全球加速服务,为有跨境访问需求的MaxCompute客户提供一套高效稳定的跨境访问加速方案. MaxCompute联合全球加速服务,为有跨境访问需求的MaxComput ...

  7. IIncrementalGenerator 增量 Source Generator 生成代码入门 从语法到语义 获取类型完全限定名

    本文告诉大家如何在使用 IIncrementalGenerator 进行增量的 Source Generator 生成代码时,如何从语法分析过程,将获取的语法 Token 转换到语义分析上,比如获取类 ...

  8. 微分流形Loring W. Tu section19 19.12 解答

    微分流形Loring W. Tu section19 19.12 解答,当然咯我自己也不知道是否严谨正确,反正就是自己的思考与想法,简单一写,欢迎友好讨论. 19.12 对于任意的\(f \in C^ ...

  9. SQL Server实战五:存储过程与触发器

      本文介绍基于Microsoft SQL Server软件,实现数据库存储过程与触发器的创建.执行.修改与删除等操作. 目录 1 交互式创建并执行--存储过程一 2 交互式创建并执行--存储过程二 ...

  10. ruby 定时器 rufus-scheduler

    安装 gem install rufus-scheduler ruby #!/usr/bin/env ruby require 'rubygems' require 'rufus-scheduler' ...