1. 引入

  • Baby Step Giant Step算法(简称BSGS),用于求解形如ax≡b(modp)a^x\equiv b(mod\ p)ax≡b(mod p)(a,b,p∈Na,b,p\in \mathbb{N}a,b,p∈N)的同余方程,即著名的离散对数问题。
  • 本文分为 (a,p)=1(a,p)=1(a,p)=1 和 (a,p)≠1(a,p)\neq 1(a,p)̸​=1 两种情况讨论。

2. 方程 ax≡b(modp)a^x\equiv b(mod\ p)ax≡b(mod p) 的解性

  • 因为若 ax≡ax+n(modp)a^{x}\equiv a^{x+n}(mod\ p)ax≡ax+n(mod p),则 ax+i≡ax+n+ia^{x+i}\equiv a^{x+n+i}ax+i≡ax+n+i。
  • 由抽屉原理以及同余的性质得,axa^xax 对 ppp 的模具有周期性,最大周期不超过 ppp。
  • 由这个周期性可得,方程有解,等价于在 [0,p)[0,p)[0,p) 中有解。
  • 由此我们只需要试图找到 [0,p)[0,p)[0,p) 中的最小自然数解,就可以得到方程是否有解,以及根据指数模的周期性得到方程的通解。
  • 下面我们只讨论求解方程的最小自然数解

3. 求解 ax≡b(modp)a^x\equiv b(mod\ p)ax≡b(mod p) (a,p)=1(a,p)=1(a,p)=1

  • Baby Step Giant Step它的名字就告诉我们,这个算法要将问题规模由大化小。
  • 我们令 t=⌈p⌉t=\lceil \sqrt{p}\rceilt=⌈p​⌉,那么我们所有 [0,p)[0,p)[0,p) 的自然数都可以包含在集合 {x∣x=it−j,i∈[1,t],j∈(0,t]}\{x|x=it-j,\ i\in [1,t],\ j \in (0,t]\}{x∣x=it−j, i∈[1,t], j∈(0,t]} 中。
  • 我们只需要验证这个集合中是否存在解,即可验证原方程是否存在解。
  • 我们考虑将方程表示为

ait−j≡b(modp)a^{it-j}\equiv b(mod\ p)ait−j≡b(mod p)

  • 根据 (a,p)=1(a,p)=1(a,p)=1,我们有

ait≡baj(modp)a^{it}\equiv ba^j(mod\ p)ait≡baj(mod p)

  • 我们发现等号两边的数我们都可以在 O(p)O(\sqrt p)O(p​) 的时间内枚举出来。
  • 我们只需要 O(p)O(\sqrt p)O(p​) 枚举出所有 bajmodp(j∈(0,t])ba^j\ mod\ p(\ j \in (0,t])baj mod p( j∈(0,t]),然后把它们插入到哈希表当中,哈希表的对应位置储存这个值对应的最大的 jjj(因为要求最小自然数解,所以在 iii 相同的时候要使 jjj 最大)。
  • 然后 O(p)O(\sqrt p)O(p​) 从小到大枚举我们需要的 aitmodp(i∈[1,t])a^{it}\ mod\ p(\ i\in [1,t])ait mod p( i∈[1,t]),并在哈希表中查询是否有相等的值,若存在则取最小的 iii 及对应最大的 jjj,并将 it−jit-jit−j 作为最小自然数解;否则若不存在则说明无自然数解。
inline int solve_BSGS(const int &a, const int &b, const int &p)
{int t = ceil(sqrt(p)); std::map<int, int> hash; //map实现hash表hash.clear(); int tmp = b; for (int i = 1; i <= t; ++i){tmp = 1LL * tmp * a % p; hash[tmp] = i; }//插入b*a^jint pw = qpow(a, t, p); tmp = pw; for (int i = 1; i <= t; ++i){if (hash.find(tmp) != hash.end())return i * t - hash[tmp]; tmp = 1LL * tmp * pw % p; }//查询a^(it)return -1; //返回无解
}

4. 求解 ax≡b(modp)a^x\equiv b(mod\ p)ax≡b(mod p) (a,p)≠1(a,p)\neq 1(a,p)̸​=1

  • 对于这个方程,我们不能像上面那样求解的原因就是 aaa 在模 ppp 意义下不存在逆元,不能将 ait−ja^{it-j}ait−j 表示为 ait×a−ja^{it}\times a^{-j}ait×a−j。
  • 那么我们从不定方程的角度分析这个同余方程。
  • 这个方程等价于

ax+py=ba^x+py=bax+py=b

  • 令 a1=(a,p)a_1=(a,p)a1​=(a,p),令原方程化为

ax−1aa1+pa1y=ba1a^{x-1}\frac{a}{a_1}+\frac{p}{a_1}y=\frac{b}{a_1}ax−1a1​a​+a1​p​y=a1​b​

  • 若此时 (a,pa1)≠1(a,\frac{p}{a_1})\neq 1(a,a1​p​)̸​=1,那么我们接着化成

ax−2a2a1a2+pa1a2y=ba1a2a^{x-2}\frac{a^2}{a_1a_2}+\frac{p}{a_1a_2}y=\frac{b}{a_1a_2}ax−2a1​a2​a2​+a1​a2​p​y=a1​a2​b​

  • 同理不断进行这样的操作,最后我们达到 (a,pa1a2…an)=1(a,\frac{p}{a_1a_2\dots a_n})=1(a,a1​a2​…an​p​)=1的目标,并将方程化为

ax−nana1a2…an+pa1a2…any=ba1a2…ana^{x-n}\frac{a^n}{a_1a_2\dots a_n}+\frac{p}{a_1a_2\dots a_n}y=\frac{b}{a_1a_2\dots a_n}ax−na1​a2​…an​an​+a1​a2​…an​p​y=a1​a2​…an​b​

  • 然后记 a′=aa1a2…ana'=\frac{a}{a_1a_2\dots a_n}a′=a1​a2​…an​a​,p′=pa1a2…anp'=\frac{p}{a_1a_2\dots a_n}p′=a1​a2​…an​p​,b′=ba1a2…anb'=\frac{b}{a_1a_2\dots a_n}b′=a1​a2​…an​b​,那么原不定方程可以化为同余方程

ax−na′≡b′(modp′)a^{x-n}a'\equiv b'(mod\ p')ax−na′≡b′(mod p′)

  • 显然 (a′,p′)=1(a',p')=1(a′,p′)=1,因此我们可以写成

ax−n≡b′(a′)−1(modp′)a^{x-n}\equiv b'(a')^{-1}(mod\ p')ax−n≡b′(a′)−1(mod p′)

  • 然后就可以用互质的方法解决了。

  • 可以发现,每次在 ppp 中除去一个最大公约数,每次都会有至少同一个质因子的次数减少 111,那么在int范围内,nnn 最多只会取到 303030。

  • 以上两个情况的时间复杂度均为 O(plog⁡2p)O(\sqrt{p}\log_2{\sqrt p})O(p​log2​p​),因为用map实现哈希,可以做到更优秀。

  • 有一些值得注意的地方:

    1. 在我们令 bbb 除以一个最大公约数 ddd 时,若 d∤bd\nmid bd∤b,结合求解二元不定方程的知识,我们判定方程无自然数解。
    2. 我们在不互质情况的化简操作中,已经假定了 x≥nx\ge nx≥n,所以方程才能写成那样的互质形式。对于 x≤nx\le nx≤n 的情况,我们应当提前枚举判断。
    3. 注意在求解方程之前将 a,ba,ba,b 对 ppp 取模,注意 aaa 取模后为 000 的情况。
    4. 对于对时间限制要求较为紧的题目,应当使用更为优秀的哈希表实现方式。
  • 模板题:SP3105 MOD - Power Modulo Inverted

  • 洛谷链接:https://www.luogu.org/problemnew/show/SP3105

  • 代码:

//map水过
#include <map>
#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>int a, p, b; inline int qpow(int b, int p, const int &mod)
{int res = 1; for (; p; p >>= 1, b = 1LL * b * b % mod)if (p & 1)res = 1LL * res * b % mod; return res;
}inline int ex_gcd(const int &a, const int &b, int &x, int &y)
{if (!b)return x = 1, y = 0, a; int res = ex_gcd(b, a % b, y, x); return y -= a / b * x, res;
}inline int solve_equ(const int &a, const int &b, const int &c)
{int x, y; int d = ex_gcd(a, b, x, y); if (c % d != 0) return -1; int mod = b / d; return (1LL * c / d * x % mod + mod) % mod;
}inline int solve_BSGS(const int &a, const int &b, const int &p)
{int t = ceil(sqrt(p)); std::map<int, int> hash; hash.clear(); int tmp = b; for (int i = 1; i <= t; ++i){tmp = 1LL * tmp * a % p; hash[tmp] = i; }int pw = qpow(a, t, p); tmp = pw; for (int i = 1; i <= t; ++i){if (hash.find(tmp) != hash.end())return i * t - hash[tmp]; tmp = 1LL * tmp * pw % p; }return -1;
}inline bool check()
{int k = 1 % p; for (int i = 0; i <= 40; ++i){if (k == b)return printf("%d\n", i), true; k = 1LL * k * a % p; }if (!a)return puts("No Solution"), true; return false;
}int main()
{while (scanf("%d%d%d", &a, &p, &b), a || p || b){a %= p, b %= p; if (check())continue; int d; int ap = 1, n = 0; bool flg = false; while ((d = std::__gcd(a, p)) != 1){++n; ap = 1LL * ap * (a / d) % p; p /= d; if (b % d){flg = true; break; }b /= d; }if (flg)puts("No Solution"); else{int res = solve_BSGS(a, 1LL * b * solve_equ(ap, p, 1) % p, p); if (res == -1)puts("No Solution"); elseprintf("%d\n", res + n); }}return 0;
}

【学习笔记】Baby Step Giant Step算法及其扩展相关推荐

  1. NOI数学:大步小步(Baby Step Giant Step,BSGS)算法

    BSGS算法求 高次同余方程:1.可爱的质数 2.计算器 BSGS算法求 高次同余方程:1.可爱的质数 2.计算器_啦啦啦32421的博客-CSDN博客 大步小步算法(BSGS)及扩展 & b ...

  2. 离散对数(Baby Step Giant Step)

    现在我来介绍一种算法叫做Baby Step Giant Step.它是用来解决如下方程最小正整数解的     其中 如果,那么我们可以先取模,即,所以在这里我们只讨论的情况. 普通Baby Step ...

  3. 【数学】Baby Step,Giant Step

    给定整数 a,b,pa,b,pa,b,p 且 a,pa,pa,p 互质,请求出高次同余方程 ax≡b(modp)a^x\equiv b\pmod pax≡b(modp) 的非负整数解. 首先, a0≡ ...

  4. BZOJ 2242([SDOI2011]计算器-Baby Step Giant Step第1题)

    2242: [SDOI2011]计算器 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 744  Solved: 289 [Submit][Statu ...

  5. bsgs(Baby Steps Giant Steps)算法

    BSGS算法(Baby Steps Giant Steps算法,大步小步算法,北上广深算法,拔山盖世算法) 适用问题 对于式子: $$x^y=z(mod_p)$$ 已知x,z,p,p为质数: 求解一个 ...

  6. 机器学习实战(Machine Learning in Action)学习笔记————06.k-均值聚类算法(kMeans)学习笔记...

    机器学习实战(Machine Learning in Action)学习笔记----06.k-均值聚类算法(kMeans)学习笔记 关键字:k-均值.kMeans.聚类.非监督学习 作者:米仓山下 时 ...

  7. 深度学习笔记(10) 优化算法(二)

    深度学习笔记(10) 优化算法(二) 1. Adam 优化算法 2. 学习率衰减 3. 局部最优的问题 1. Adam 优化算法 Adam代表的是 Adaptive Moment Estimation ...

  8. 深度学习笔记(9) 优化算法(一)

    深度学习笔记(9) 优化算法(一) 1. Mini-batch 梯度下降 2. 指数加权平均数 3. 动量梯度下降法 4. 均方根反向传播 1. Mini-batch 梯度下降 把训练样本放大巨大的矩 ...

  9. 【C++ Primer 学习笔记】: 容器和算法之【泛型算法】

    本系列博客主要是在学习 C++ Primer 时的一些总结和笔记. [C++ Primer 学习笔记]: 容器和算法之[泛型算法] 本文地址:http://blog.csdn.net/shanglia ...

  10. 小猫爪:i.MX RT1050学习笔记15-FlexSPI-FLASH使用3-KEIL FLASH算法中的使用

    小猫爪:i.MX RT1050学习笔记15-FlexSPI-FLASH使用3-KEIL FLASH算法中的使用 1 前言 2 FLASH算法解析 2.1 初始化Init 2.2 写操作 END 1 前 ...

最新文章

  1. 如何用Python做三阶拼图?
  2. 20T数据、百万奖金,同济和武大摘得开放数据创新应用大赛桂冠!
  3. Log4net中的RollingFileAppender解析
  4. 使用OpenVas漏扫
  5. ES聚合底层机制-bucket深的话采用广度优先更好,而如果是年度统计还是深度优先好...
  6. java get与post区别_HTTP请求(GET与POST区别)和响应
  7. 使用pycharm创建一个项目 利用自己建好的虚拟环境
  8. JavaScript高级程序设计(第三版)学习笔记22、24、25章
  9. 慎用 supportedRuntime
  10. SpringCloud核心技术 | 初识SpringCloud微服务解决方案
  11. MapReduce 学习指南
  12. 浅谈前端JavaScript编程风格
  13. vite和webpack的区别
  14. 小白都能看懂的go语言包管理工具DEP详解
  15. 一种很欣赏的操盘手法
  16. 【布局优化】基于人工蜂群算法的无线传感器网(WSN)覆盖优化matlab源码
  17. 读书笔记-高调做事低调做人 把握好度
  18. CSS传统布局所用的元素
  19. “不想天天昧着良心吹牛了”,创业者退场,VR进入洗牌期
  20. RS232转RS484接线图

热门文章

  1. 计算机上静音快捷键是什么,电脑静音快捷键是什么(电脑静音快捷键怎么设置)...
  2. 计算机键盘中复制粘贴快捷键,电脑复制粘贴快捷键
  3. mrc mcr 与 bic orr 含义及用法示例
  4. tcl电视显示服务器异常1500,TCL 智能液晶电视常见故障分析检修实例
  5. 少有人走的路:心智成熟的旅程
  6. linux安装vscode(中标麒麟+龙芯CPU)
  7. 推荐PC端一款非常好用的解压缩软件
  8. 读研攻略(6)—会议纪要
  9. 【Pytorch】测试单张图片(调用transforms)
  10. 别做正常的傻瓜-读后感