\(BSGS(baby-step-giant-step)\)算法是用来解高次同余方程的最小非负整数解的算法,即形如这个的方程:

$a^x\equiv b(mod\ p)$
其中$p$为质数(其实只要($(a,p)=1$即可)
首先考虑暴力怎么解:由费马小定理可知$a^{p-1}\equiv 1(mod\ p)$,也就是说如果在$[0,p-1]$内无解的话,方程就是无解的。所以我们从小到大枚举$[0,p-1]$中的每一个数,满足方程就结束。但是这里$p-1$并不一定是最小正周期,这个可以由**[阶](https://baike.baidu.com/item/%E9%98%B6/5214104#5)**的定义推出,有兴趣的同学可以去看一下。
但是这个方法在$p$很大时就$GG$啦,于是我们考虑优化一下:
设$x=im-j$,其中$m=\left \lceil \sqrt{p} \right \rceil$。那么我们开始对方程进行变形:
$a^{im}\equiv a^jb(mod\ p)$
显然,$j$是余数,所以有$0\leqslant j \leqslant m-1$,也就是说右边的值最多只有$m$个,而$i$的最大值也只为$m$。所以我们暴力枚举$j$,把$a^jb$存到$map$或哈希表里,再从小到大暴力枚举$i$,每次在哈希表里查一下有没有$a^jb$使得方程成立就可以辣。
同时,有一个很妙的事情:我们枚举$j$时是从小到大枚举的,每次插入到哈希表头的前面,所以表的越靠前的元素的$j$值是越大的,而我们正好想要$j$尽量大,一石二鸟,每次查到一个值就可以直接$return$了。这样查询的近似复杂度就降到$O(1)$了。
要注意先特判一下$x=0$的情况。
板子代码:
``` cpp
namespace Ha { //哈希表
int tot, h[MOD+5], ne[MOD+5];
ll ha[MOD+5];
void insert(ll x, ll num) { //插入操作
ll t = num%MOD;
p[++tot] = x, ha[tot] = num, ne[tot] = h[t], h[t] = tot;
}
ll query(ll tar) { //查询操作
for(int i = h[tar%MOD]; i != -1; i = ne[i])
if(ha[i] == tar) return p[i];
return -1;
}
}
using namespace Ha;
ll bsgs(ll a, ll b, ll p) {
a %= p, b %= p;
if(a == 0 && b != 0) return -1; //a%p==0时显然无解
if(a == 0 && b == 0) return 1;
if(b == 1) return 0;
ll m = ceil(sqrt((double)p)), q = 1, x = 1;
memset(h, -1, sizeof h); //记得清空
for(ll j = 0; j $ta^{x-cnt}\equiv b'(mod\ c')$,其中$a,c'$互质
然后我们就将它转化为标准的$BSGS$可解决的问题啦。
记得特判一下$x\leqslant cnt$的情况(~~为什么留给读者自己思考~~)
粘一下代码:
```cpp
ll bsgs(ll a, ll b, ll p) {
a %= p, b %= p;
if(a == 0 && b != 0) return -1;
if(a == 0 && b == 0) return 1;
if(b == 1) return 0;
ll d = 1, t = 1, cnt = 0, m = ceil(sqrt(p)), q = 1;
while((d = gcd(a, p)) != 1) {
if(b%d) return -1;
cnt++, b /= d, p /= d, t = t*(a/d)%p;
if(b == t) return cnt; //特判
}
memset(h, -1, sizeof h);
for(ll i = 0; i 放一道例题:洛谷/BZOJ。这应该算是板子了吧→_→

AC代码:

#include <bits/stdc++.h>

#define MOD 1000007
#define ll long long int T, k;
ll p[MOD+5]; namespace Ha {
int tot, h[MOD+5], ne[MOD+5];
ll ha[MOD+5];
} using namespace std;
using namespace Ha; void insert(ll x, ll num) {
ll t = num%MOD;
p[++tot] = x, ha[tot] = num, ne[tot] = h[t], h[t] = tot;
} ll query(ll tar) {
for(int i = h[tar%MOD]; i != -1; i = ne[i])
if(ha[i] == tar) return p[i];
return -1;
} ll bsgs(ll a, ll b, ll p) {
a %= p, b %= p;
if(a == 0) return -1;
if(b == 1) return 0;
ll m = ceil(sqrt((double)p)), q = 1, x = 1;
memset(h, -1, sizeof h);
for(ll i = 0; i < m; ++i) insert(i, q*b%p), q = q*a%p;
for(ll i = 1, j; i <= m; ++i) {
x = x*q%p, j = query(x);
if(j != -1) return i*m-j;
}
return -1;
} ll fpow(ll x, ll p, ll mod) {
ll base = x%mod, ret = 1LL;
while(p) {
if(p&1) ret = ret*base%mod;
base = base*base%mod;
p >>= 1;
}
return ret;
} ll inv(ll x, ll p) {
return fpow(x, p-2, p);
} int main() {
cin >> T >> k;
ll x, y, z, inv_y, ans;
while(T--) {
cin >> x >> y >> z;
if(k == 1) cout << fpow(x, y, z) << endl;
else if(k == 2) {
if(x%z == 0) cout << "Orz, I cannot find x!" << endl;
else cout << y*inv(x, z)%z << endl;
}
else {
ans = bsgs(x, y, z);
if(ans == -1) cout << "Orz, I cannot find x!" << endl;
else cout << ans << endl;
}
}
return 0;
}

BSGS及扩展BSGS算法及例题的更多相关文章

  1. BSGS与扩展BSGS

    BSGS \(BSGS\)算法又称大步小步\((Baby-Step-Giant-Step)\)算法 \(BSGS\)算法主要用于解以下同余方程 \[A^x\equiv B(mod\ p)\]其中\(( ...

  2. BSGS和扩展BSGS

    BSGS: 求合法的\(x\)使得\(a ^ x \quad mod \quad p = b\) 先暴力预处理出\(a^0,a^1,a^2.....a^{\sqrt{p}}\) 然后把这些都存在map ...

  3. BSGS及扩展BSGS总结(BSGS,map)

    蒟蒻哪里有什么总结,只能点击%YL% 还有这位ZigZagK大佬的blog \(\mbox{BSGS}\) 模板题:洛谷P3846 [TJOI2007]可爱的质数 给定\(a,b\)和模数\(\mbo ...

  4. BSGS及其扩展

    目录 定义 原理 朴素算法 数论分块 例题 Luogu2485 [SDOI2011]计算器 题解 代码 扩展 例题 Luogu4195 [模板]exBSGS/Spoj3105 Mod 代码 之前写了一 ...

  5. BSGS&扩展BSGS

    BSGS 给定\(a,b,p\),求\(x\)使得\(a^x\equiv b \pmod p\),或者说明不存在\(x\) 只能求\(\gcd(a,p)=1\)的情况 有一个结论:如果有解则必然存在\ ...

  6. POJ 3243 Clever Y 扩展BSGS

    http://poj.org/problem?id=3243 这道题的输入数据输入后需要将a和b都%p https://blog.csdn.net/zzkksunboy/article/details ...

  7. bzoj 3283 扩展BSGS + 快速阶乘

    T2  扩展BSGS T3 快速阶乘 给定整数n,质数p和正整数c,求整数s和b,满足n! / pb = s mod pc 考虑每次取出floor(n/p)个p因子,然后将问题转化为子问题. /*** ...

  8. poj 3243 Clever Y && 1467: Pku3243 clever Y【扩展BSGS】

    扩展BSGS的板子 对于gcd(a,p)>1的情况 即扩展BSGS 把式子变成等式的形式: \( a^x+yp=b \) 设 \( g=gcd(a,p) \) 那么两边同时除以g就会变成: \( ...

  9. 扩展BSGS求解离散对数问题

    扩展BSGS用于求解axΞb mod(n) 同余方程中gcd(a,n)≠1的情况 基本思路,将原方程转化为a与n互质的情况后再套用普通的BSGS求解即可 const int maxint=((1< ...

随机推荐

  1. c/c++ 多线程 一个线程等待某种事件发生

    多线程 一个线程等待某种事件发生 背景:某个线程在能够完成其任务之前可能需要等待另一个线程完成其任务. 例如:坐夜间列车,为了能够不坐过站, 1,整夜保持清醒,但是这样你就会非常累,不能够睡觉. 2, ...

  2. Linux学习历程——Centos 7 uptime 、free命令

    一.命令介绍 uptime命令 uptime命令用于查看系统负载信息以及系统运行时间等. free命令 free命令用于查看当前系统中内存使用量信息. 二.实例 uptime命令实例 直接运行 upt ...

  3. Win10 Service'MongoDB Server' failed to start. Verify that you have sufficient privileges to start system services【简记】

    最近工作中有需要用到 MongoDB数据库,以前用的3.*的版本,这次用的是较新4.0.6的版本,然后去官网下载安装. 安装到一半,就弹出如下提示,说是"MongoDB Server&quo ...

  4. LeetCode算法题-Longest Continuous Increasing Subsequence(Java实现)

    这是悦乐书的第286次更新,第303篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第154题(顺位题号是674).给定未排序的整数数组,找到最长连续增加子序列的长度.例如 ...

  5. socket粘包问题解决

    粘包client.send(data1)client.send(data2)这两次send紧挨在一起,处理的时候会放在一起发过去在Linux里每次都粘包,Windows里面某次会出现粘包在两次send ...

  6. 超哥笔记 -- 用户管理、权限设置、进程管理、中文配置、计划任务和yum源配置(5)

    一 网卡配置 ifconfig 查询.设置网卡和ip等参数 ifup,ifdown    脚本命令,更简单的方式启动关闭网络 ip 符合指令,直接修改上述功能 网络配置文件: /etc/sysconf ...

  7. 【Linux基础】grep命令

    1.简介 grep是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来. 命令格式:grep [option] pattern file 2.常用参数与举例: -e :  使用P ...

  8. lsof -i

    https://www.cnblogs.com/sparkbj/p/7161669.html 主要命令

  9. Netty(RPC高性能之道)原理剖析

    转载:http://blog.csdn.net/zhiguozhu/article/details/50517551 1,Netty简述 Netty 是一个基于 JAVA NIO 类库的异步通信框架, ...

  10. CSAPP:第八章 异常控制流2

    CSAPP:第八章 异常控制流2 关键点:进程控制.信号 8.4 进程控制8.5 信号 8.4 进程控制   Unix提供了大量从C程序中操作进程的系统调用.8.4.1 获取进程ID  每个进程都有一 ...