「算法笔记」BSGS 与 exBSGS
一、离散对数
给定 \(a,b,m\),存在一个 \(x\),使得
\(\displaystyle a^x\equiv b\pmod m\)
则称 \(x\) 为 \(b\) 在模 \(m\) 意义下以 \(a\) 为底的 离散对数。
二、BSGS
离散对数:求解关于 \(x\) 的方程 \(a^x\equiv b\pmod m\)。
基本思想:(假设 \(\gcd(a,m)=1\),那么 \(a\) 在模 \(m\) 意义下存在逆元)
考虑类似分块的一个想法。首先设定一个常量 \(t\)。
设 \(x=qt+r\)(\(0\leq r<t\)),预处理所有 \(a^{qt}\) 模 \(m\) 的值,存到 Hash 表 / map 中。询问时,枚举 \(r\),因为 \(a^{qt+r}\equiv b\pmod m\Leftrightarrow a^{qt}\equiv b\cdot a^{-r}\pmod m\),所以判断是否存在 \(a^{qt}\equiv b\cdot a^{-r}\pmod m\) 即可。
预处理的复杂度为 \(\mathcal{O}(\frac{m}{t})\),单次询问的复杂度为 \(\mathcal{O}(t)\)。取 \(t=\sqrt{m}\),则复杂度为 \(\mathcal{O}(\sqrt{m})\)。
用 map 会多一个 \(\log\)。
不同的写法:如果不想求 \(a^{-r}\),设 \(x=qt-r\)(\(0\leq q,r<t\)), \(a^{qt-r}\equiv b\pmod m\Leftrightarrow a^{qt}\equiv b\cdot a^r\pmod m\),预处理 \(b\cdot a^r\) 模 \(m\) 的值,枚举 \(q\),判断是否能找到对应的 \(r\)。
//Luogu P3846
#include<bits/stdc++.h>
#define int long long
using namespace std;
map<int,int>mp;
int a,b,p,ans;
int mul(int x,int n,int mod){
int ans=mod!=1;
for(x%=mod;n;n>>=1,x=x*x%mod)
if(n&1) ans=ans*x%mod;
return ans;
}
int BSGS(int a,int b,int p){ //设 x=qt-r,预处理 b*(a^r)%p,枚举 q,判断是否存在 a^{qt}%p=b*{a^r}%p
a%=p,b%=p,mp.clear();
if(!a) return !b?0:-1;
int t=ceil(sqrt(p)),x=b;
for(int i=0;i<=t;i++) mp[x]=i,x=x*a%p; //枚举 r,预处理 b*(a^r)%p 的值
a=mul(a,t,p),x=a;
for(int i=1;i<=t;i++){ //枚举 q
if(mp.count(x)) return i*t-mp[x]; //判断是否能找到对应的 r。若找到了,则 x=qt-r 为 x 的一个解
x=x*a%p;
}
return -1;
}
signed main(){
scanf("%lld%lld%lld",&p,&a,&b);
ans=BSGS(a,b,p);
if(~ans) printf("%lld\n",ans);
else puts("no solution");
return 0;
}
二、exBSGS
求解关于 \(x\) 的方程 \(a^x\equiv b\pmod m\)。\(m\) 可取任意数。
BSGS:\(\gcd(a,m)=1\),\(a\) 在模 \(m\) 意义下存在逆元,可令等式右侧出现 \(a\) 的幂次。
扩展 BSGS:考虑 \(\gcd(a,m)\neq 1\) 的情况。一个想法是,将它转化为 \(\gcd(a,m)=1\)。
设 \(d=\gcd(a,m)\)。\(a^x\equiv b\pmod m\Leftrightarrow a^x+km=b\),根据裴蜀定理,方程有解当且仅当 \(\gcd(a,m)\mid b\)。所以,若 \(d\nmid b\),则原方程无解。
否则,令方程两边同时除以 \(d\),得:
\(\displaystyle\frac{a}{d}\cdot a^{x-1}+k\cdot\frac{m}{d}=\frac{b}{d}\)
此时,若 \(\gcd(a,m)\neq 1\),则令 \(x'=x-1,m'=\frac{m}{d},b'=\frac{b}{d}\),重复上述步骤,于是可以一直做下去,直到 \(\gcd(a,m')=1\)。
不妨设重复了 \(g\) 次,每次求得的 \(d=\gcd(a,m')\) 分别为 \(d_1,d_2,\cdots,d_g\)。记 \(\prod_{i=1}^g d_i =D\),原式就是:
\(\displaystyle\frac{a^g}{D}\cdot a^{x-g}\equiv \frac{b}{D}\pmod {\frac{m}{D}}\)
那么就令 \(a'=a,b'=\frac{b}{D},m'=\frac{m}{D}\),跑一遍 BSGS 即可(在枚举 \(a^{qt}\) 判断时乘上 \(\frac{a^g}{D}\),对应代码中的 ad。最后答案加上 \(g\) 就行了)。
//Luogu P4195
#include<bits/stdc++.h>
#define int long long
using namespace std;
map<int,int>mp;
int a,b,p,ans;
int mul(int x,int n,int mod){
int ans=mod!=1;
for(x%=mod;n;n>>=1,x=x*x%mod)
if(n&1) ans=ans*x%mod;
return ans;
}
int BSGS(int a,int b,int p,int ad){
a%=p,b%=p,mp.clear();
if(!a) return !b?0:-1;
int t=ceil(sqrt(p)),x=b;
for(int i=0;i<=t;i++) mp[x]=i,x=x*a%p;
a=mul(a,t,p),x=a*ad%p; //upd: 原来的 x=a 改为了 x=a*ad%p
for(int i=1;i<=t;i++){
if(mp.count(x)) return i*t-mp[x];
x=x*a%p;
}
return -1;
}
int exBSGS(int a,int b,int p){
a%=p,b%=p;
int g=0,ad=1,d,ans;
while((d=__gcd(a,p))!=1){
if(b%d) return -1;
g++,b/=d,p/=d,ad=(ad*a/d)%p;
if(ad==b) return g;
}
if(~(ans=BSGS(a,b,p,ad))) return ans+g;
return -1;
}
signed main(){
while(~scanf("%lld%lld%lld",&a,&p,&b)){
if(!a&&!b&&!p) break;
ans=exBSGS(a,b,p);
if(~ans) printf("%lld\n",ans);
else puts("No Solution");
}
return 0;
}
建议把 map 改成 Hash 表 QAQ。
「算法笔记」BSGS 与 exBSGS的更多相关文章
- 「算法笔记」快速数论变换(NTT)
一.简介 前置知识:多项式乘法与 FFT. FFT 涉及大量 double 类型数据操作和 \(\sin,\cos\) 运算,会产生误差.快速数论变换(Number Theoretic Transfo ...
- 「算法笔记」树形 DP
一.树形 DP 基础 又是一篇鸽了好久的文章--以下面这道题为例,介绍一下树形 DP 的一般过程. POJ 2342 Anniversary party 题目大意:有一家公司要举行一个聚会,一共有 \ ...
- 「算法笔记」2-SAT 问题
一.定义 k-SAT(Satisfiability)问题的形式如下: 有 \(n\) 个 01 变量 \(x_1,x_2,\cdots,x_n\),另有 \(m\) 个变量取值需要满足的限制. 每个限 ...
- 「算法笔记」Polya 定理
一.前置概念 接下来的这些定义摘自 置换群 - OI Wiki. 1. 群 若集合 \(s\neq \varnothing\) 和 \(S\) 上的运算 \(\cdot\) 构成的代数结构 \((S, ...
- 「算法笔记」状压 DP
一.关于状压 dp 为了规避不确定性,我们将需要枚举的东西放入状态.当不确定性太多的时候,我们就需要将它们压进较少的维数内. 常见的状态: 天生二进制(开关.选与不选.是否出现--) 爆搜出状态,给它 ...
- 「算法笔记」旋转 Treap
一.引入 随机数据中,BST 一次操作的期望复杂度为 \(\mathcal{O}(\log n)\). 然而,BST 很容易退化,例如在 BST 中一次插入一个有序序列,将会得到一条链,平均每次操作的 ...
- 「算法笔记」FHQ-Treap
右转→https://www.cnblogs.com/mytqwqq/p/15057231.html 下面放个板子 (禁止莱莱白嫖板子) P3369 [模板]普通平衡树 #include<bit ...
- 「算法笔记」Min_25 筛
戳 这里(加了密码).虽然写的可能还算清楚,但还是不公开了吧 QwQ. 真的想看的 私信可能会考虑给密码 qwq.就放个板子: //LOJ 6053 简单的函数 f(p^c)=p xor c #inc ...
- 「算法笔记」快速傅里叶变换(FFT)
一.引入 首先,定义多项式的形式为 \(f(x)=\sum_{i=0}^n a_ix^i\),其中 \(a_i\) 为系数,\(n\) 为次数,这种表示方法称为"系数表示法",一个 ...
随机推荐
- Java中static关键字声明的静态内部类与非静态内部类的区别
(1)内部静态类不需要有指向外部类的引用.但非静态内部类需要持有对外部类的引用.(2)非静态内部类能够访问外部类的静态和非静态成员.静态类不能访问外部类的非静态成员.他只能访问外部类的静态成员.(3) ...
- IDEA高颜值之最吸引小姐姐插件集合!让你成为人群中最靓的那个崽!
经常有小伙伴会来找TJ君,可能觉得TJ君比较靠谱,要TJ君帮忙介绍女朋友.TJ君一直觉得程序猿是天底下最可爱的一个群体,只不过有时候不善于表达自己的优秀,所以TJ君今天准备介绍几款酷炫实用的IDEA插 ...
- act.四级
act的词源是do, 干着或干了的事情也可以叫act.action: doing sth; act: n. action, v. do; activity: busy, energetic, or占据 ...
- day02 Linux基础
day02 Linux基础 1.什么是服务器 服务器,也称伺服器,是提供计算服务的设备.由于服务器需要响应服务请求,并进行处理,因 此一般来说服务器应具备承担服务并且保障服务的能力. windows: ...
- npm下载错误解决办法
解决办法:删除npmrc文件. 使用镜像 镜像使用方法(三种办法任意一种都能解决问题,建议使用第三种,将配置写死,下次用的时候配置还在):1.通过config命令12npm config set re ...
- CentOS Linux下编译安装MySQL
本文参考张宴的Nginx 0.8.x + PHP 5.2.13(FastCGI)搭建胜过Apache十倍的Web服务器(第6版)[原创]完成.所有操作命令都在CentOS 6.4 64位操作系统下实践 ...
- Spring(4):Mybatis和Spring整合
第一步:创建数据库 MySQL代码 1 CREATE DATABASE `mybatis` ; 2 3 USE `mybatis`; 4 5 CREATE TABLE `user` ( 6 `id` ...
- 【Linux】【Basis】文件
refer to: https://en.wikipedia.org/wiki/POSIX refer to: https://en.wikipedia.org/wiki/Unix_file_type ...
- 动态规划系列(零)—— 动态规划(Dynamic Programming)总结
动态规划三要素:重叠⼦问题.最优⼦结构.状态转移⽅程. 动态规划的三个需要明确的点就是「状态」「选择」和「base case」,对应着回溯算法中走过的「路径」,当前的「选择列表」和「结束条件」. 某种 ...
- Centos 常用指令
1.*.tar 用 tar xvf 解压 2.*.gz 用 gzip d或者gunzip 解压 3.*.tar.gz和*.tgz 用 tar xzf 解压 4.*.bz2 用 bzip2 d或者用 ...