算法学习笔记(10): BSGS算法及其扩展算法
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算法及其扩展算法的更多相关文章
- 算法学习笔记(8.1): 网络最大流算法 EK, Dinic, ISAP
网络最大流 目录 网络最大流 EK 增广路算法 Dinic ISAP 作者有话说 前置知识以及更多芝士参考下述链接 网络流合集链接:网络流 最大流,值得是在不超过管道(边)容量的情况下从源点到汇点最多 ...
- 算法学习笔记(9): 中国剩余定理(CRT)以及其扩展(EXCRT)
扩展中国剩余定理 讲解扩展之前,我们先叙述一下普通的中国剩余定理 中国剩余定理 中国剩余定理通过一种非常精巧的构造求出了一个可行解 但是毕竟是构造,所以相对较复杂 \[\begin{cases} x ...
- Johnson 全源最短路径算法学习笔记
Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...
- 算法学习笔记(3): 倍增与ST算法
倍增 目录 倍增 查找 洛谷P2249 重点 变式练习 快速幂 ST表 扩展 - 运算 扩展 - 区间 变式答案 倍增,字面意思即"成倍增长" 他与二分十分类似,都是基于" ...
- Miller-Rabin 与 Pollard-Rho 算法学习笔记
前言 Miller-Rabin 算法用于判断一个数 \(p\) 是否是质数,若选定 \(w\) 个数进行判断,那么正确率约是 \(1-\frac{1}{4^w}\) ,时间复杂度为 \(O(\log ...
- C / C++算法学习笔记(8)-SHELL排序
原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...
- Manacher算法学习笔记 | LeetCode#5
Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...
- Effective STL 学习笔记 Item 34: 了解哪些算法希望输入有序数据
Effective STL 学习笔记 Item 34: 了解哪些算法希望输入有序数据 */--> div.org-src-container { font-size: 85%; font-fam ...
- 【HLSL学习笔记】WPF Shader Effect Library算法解读之[DirectionalBlur]
原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[DirectionalBlur] 方位模糊是一个按照指定角度循环位移并叠加纹理,最后平均颜色值并输出的一种特效. ...
- 【HLSL学习笔记】WPF Shader Effect Library算法解读之[Embossed]
原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[Embossed] Embossed(浮雕效果) 浮雕效果主要有两个参数:Amount和Wid ...
随机推荐
- MQTT实战系列(一)——MQTT简介
随着移动互联网以及物联网应用的蓬勃发展,阿里云推出微消息队列 MQTT,从而实现端(浏览器.Android.iOS.智能设备.直播互动.车联网)与云的双向通信,通过消息实现万物互联. MQTT (Me ...
- 耗时又繁重的SQL诊断优化,以后就都交给数据库自治服务DAS吧!
在我们业务系统中,数据库越来越扮演着举足轻重的角色. 和其它公司一样,在阿里巴巴业务场景下,大部分业务跟数据库有着非常紧密的关系,数据库一个微小的抖动都有可能对业务造成非常大的影响, 如何让数据库更稳 ...
- Linux系统诊断-内存基础
简介: Linux系统诊断-内存基础 1. 背景 谈及linux内存,很多时候,我们会关注free,top等基础命令.当系统遇到异常情况时,内存问题的根因追溯,现场诊断时,缺乏深层次的debug能力. ...
- OpenYurt 如何 “0 侵入” 攻破云边融合难点
简介: 随着 5G.IoT.直播.CDN 等行业和业务的发展,越来越多的算力和业务开始下沉到距离数据源或者终端用户更近的位置,以期获得很好的响应时间和成本,这是一种明显区别于传统中心模式的计算方式-- ...
- 使用 Arthas 排查开源 Excel 组件问题
简介: 有了实际的使用之后,不免会想到,Arthas 是如何做到在程序运行时,动态监测我们的代码的呢?带着这样的问题,我们一起来看下 Java Agent 技术实现原理. 背景介绍 项目中有使 ...
- [SVG] JS 动态加载 svg 修改 svg 属性
svg 概念一览: https://javascript.ruanyifeng.com/htmlapi/svg.html加载 svg: // for example: $('body').load(' ...
- github 解决推拉代码提示 REMOTE HOST IDENTIFICATION HAS CHANGED 失败
本文记录最近 github 推送或拉取代码时提示 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! 而失败的解决方法 报错提示如下 @@@@@@@@@@ ...
- C++多态与虚拟:运算符重载(Operator Overloading)
运算符重载:与function overloading异曲同工的是,C++提供所谓的Operator overloading.所谓operators是像 +(加)-(減)*(乘)/(除)>&g ...
- ABAP 7.55 新特性 (二) ABAP SQL部分
上一篇文章ABAP 7.55 新特性 (一)介绍了ABAP 7.55中除ABAP SQL外的更新内容,本篇是剩余的ABAP SQL更新部分. 本文链接:https://www.cnblogs.com/ ...
- python3使用dpkt生成PCMA格式rtp流
操作系统 :CentOS 7.6_x64 Python版本:3.9.12 dpkt版本:1.9.8 PCMA编码是VoIP通信中常见的格式,今天整理下CentOS7环境下,python3如何使用dpk ...