之前写了一篇关于BSGS的学习笔记。因为太过老旧,就想修改一些错误,顺便添上扩展BSGS的部分。可惜博客园不能对已发布的随笔修改编辑器,索性重新发出来。旧文已删。

定义

Baby-Step-Giant-Step算法,简称BSGS算法,又称大步小步算法,用于求方程\(a^x\equiv b(\text{mod }c)\)的最小非负整数解,此过程又称离散对数。

普通BSGS算法只能解决\((a,c)=1\)的情况,对其进行扩展之后则没有这个限制。

原理

当\((a,c)=1\)时,若\(c|a\)且\(b\not=0\),则显然无解。若\(c\not|\ \ a\),有\(a^{c-1}\equiv 1(\text{mod }c)\),即\(c-1\)是一个循环节。因此如果方程有解,必定在\([0,c-2]\)中。

朴素算法

由此得到一个朴素的算法。枚举\([0,c-2]\)中每一个数,如果相等就输出答案。时间复杂度\(O(c)\)。考虑对其进行优化,引入数论分块的思想。

数论分块

设\(x=i\times m+j(0\leq j<m)\),原方程改写为\(a^{im+j}\equiv b(\text{mod }c)\)。令\(D(i)=a^{im}\),原方程进一步改写为\(D(i)\cdot a^j\equiv (\text{mod }c)\)。

暴力枚举每个可能的\(i\),用扩展欧几里得可以求出\(a^j\)。可是我们依然无法求得\(j\)。此时注意到\(j\)的所有可能取值只有\(m\)个,因此我们预先将所有的\(a^j\)存入一个哈希表,当我们确定\(a^j\)时,直接查表可以\(O(1)\)得到是否有对应的\(j\),以及对应的\(j\)是多少。暴力枚举复杂度\(O(ilog_2c)\),预处理复杂度\(O(m)\),总复杂度\(O(ilog_2c+m)\)。注意到\(x\approx i\times m\),因此当\(m\)取\(\sqrt c\)时(事实上由于\(\log_2c\)的存在不是很严谨)总复杂度最小,为\(O(\sqrt c\ \log_2c)\)。

至此,我们采用以空间换时间,最后通过分块的思想将该算法优化至根号级别。

例题

Luogu2485 [SDOI2011]计算器

题目链接

题解

操作1:快速幂;操作2:扩展欧几里得;操作3:普通BSGS。

代码

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define LL long long
using namespace std;
using namespace std::tr1;
unordered_map<int,int>mp;
int t,k;
inline LL qpow(LL a,LL k,LL p){
LL ans=1;
for(;k;a=a*a%p,k>>=1){if(k&1){ans=ans*a%p;}}
return ans;
}
inline LL inv(LL a,LL p){return qpow(a,p-2,p);}
inline LL BSGS(LL a,LL b,LL p){
if(p==1&&b==0)return 0;
if(b==1)return 0;
if(a==0||b==0){
if(a==0&&b==0)return 1;
return -1;
}
LL i,y=(LL)sqrt(p),tmp,ans;
mp.clear();
for(i=0,tmp=1;i<y;i++,tmp=tmp*a%p){
mp[b*tmp%p]=i;
}
for(i=1,ans=tmp;y*(i-1)+1<=p-2;i++,ans=ans*tmp%p){
if(mp.find(ans)==mp.end())continue;
if(i*y-mp[ans]<0)continue;
return i*y-mp[ans];
}
return -1;
}
int main()
{
int i,j;
LL y,z,p,ans;
cin>>t>>k;
while(t--){
scanf("%lld%lld%lld",&y,&z,&p);
y%=p;
if(k==1){printf("%lld\n",qpow(y,z,p));}
else if(k==2){
z%=p;
if(y==0&&z){cout<<"Orz, I cannot find x!\n";continue;}
printf("%lld\n",z*inv(y,p)%p);
}
else{
z%=p;
ans=BSGS(y,z,p);
if(ans==-1){cout<<"Orz, I cannot find x!\n";continue;}
printf("%lld\n",ans);
}
}
return 0;
}

扩展

此时\(c\)不一定是质数,无法保证解的循环性。因此试图将该问题转化为普通BSGS问题。

首先给出一个判定解是否存在的方法:

当\((a,c)\not|\ \ b \quad \text{and}\quad b\not=1\)时,方程无自然数解。

因此,当\((a,c)|b\)时,不妨设\(G=(a,c)\)。

\[a^{x-1}\frac aG\equiv \frac bG(\text{mod }\frac cG)
\]
\[\Longrightarrow a^{x-1}\equiv\frac bG(\frac aG)^{-1}(\text{mod }\frac cG)
\]

令\(x'=x-1,b'=\frac bG(\frac aG)^{-1},c'=\frac cG\),则有

\[a^{x'}\equiv b'(\text{mod }c')
\]

递归进行以上过程,直至\((a,c)=1\),使用普通BSGS即可。

例题

Luogu4195 【模板】exBSGS/Spoj3105 Mod

题目链接

代码

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define LL long long
using namespace std;
using namespace std::tr1;
unordered_map<int,int>mp;
#define _BUFFERSIZE 65536
static size_t _pos = _BUFFERSIZE, _len; static char _buf[_BUFFERSIZE];
inline void _getc(char &c){
if(_pos==_BUFFERSIZE){
_pos=0;
_len=fread(_buf,1,_BUFFERSIZE,stdin);
}
c=_pos<_len?_buf[_pos++]:0;
}
template<typename T>
void read(T& x){
x=0;
char c;
do _getc(c); while(!isdigit(c));
do{
x=x*10+(c-'0');
_getc(c);
}while(isdigit(c));
}
void exgcd(LL a,LL b,LL &x,LL &y){
if(!b){x=1;y=0;return;}
exgcd(b,a%b,x,y);
LL tmp=x;x=y;y=tmp-a/b*y;
}
LL inv(LL a,LL p){
LL x,y;
exgcd(a,p,x,y);
return (x%p+p)%p;
}
LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
LL BSGS(LL a,LL b,LL p){
if(p==1&&b==0)return 0;
if(b==1)return 0;
if(a==0||b==0){
if(a==0&&b==0)return 1;
return -1;
}
LL i,y=(LL)sqrt(p),tmp,ans;
mp.clear();
for(i=0,tmp=1;i<y;i++,tmp=tmp*a%p){
mp[b*tmp%p]=i;
}
for(i=1,ans=tmp;y*(i-1)+1<=p-2;i++,ans=ans*tmp%p){
if(mp.find(ans)==mp.end())continue;
if(i*y-mp[ans]<0)continue;
return i*y-mp[ans];
}
return -1;
}
LL exBSGS(LL a,LL b,LL p){
a%=p;b%=p;
if(b==1)return 0;
if(a==0){if(b==0){return 1;}return -1;}
if(b==0){
LL ans=0,d;
while((d=gcd(a,p))!=1){
ans++;p/=d;
if(p==1)return ans;
}
return -1;
}
LL ans,d,cnt=0;
while((d=gcd(a,p))!=1){
if(b%d)return -1;
cnt++;
p/=d;b=b/d*inv(a/d,p)%p;
}
ans=BSGS(a,b,p);
if(ans==-1)return -1;
return cnt+ans;
}
int main()
{
int i,j;
LL a,p,b,ans;
for(;;){
read(a);read(p);read(b);
if(!(a||b||p))break;
ans=exBSGS(a,b,p);
if(ans==-1){printf("No Solution\n");}
else{printf("%lld\n",ans);}
}
return 0;
}

BSGS及其扩展的更多相关文章

  1. BSGS与扩展BSGS

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

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

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

  3. BSGS和扩展BSGS

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

  4. BSGS及扩展BSGS算法及例题

    \(BSGS(baby-step-giant-step)\)算法是用来解高次同余方程的最小非负整数解的算法,即形如这个的方程: \(a^x\equiv b(mod\ p)\) 其中\(p\)为质数(其 ...

  5. Codeforces 1106F Lunar New Year and a Recursive Sequence (数学、线性代数、线性递推、数论、BSGS、扩展欧几里得算法)

    哎呀大水题..我写了一个多小时..好没救啊.. 数论板子X合一? 注意: 本文中变量名称区分大小写. 题意: 给一个\(n\)阶递推序列\(f_k=\prod^{n}_{i=1} f_{k-i}b_i ...

  6. BSGS 和扩展

    BSGS BSGS,全称叫 BabyStepGiantStep,也就是大步小步 其实还是比较暴力的 它可以\(O(\sqrt p)\)的复杂度内解出: \[a^x\equiv n\pmod p,\gc ...

  7. 数论算法 剩余系相关 学习笔记 (基础回顾,(ex)CRT,(ex)lucas,(ex)BSGS,原根与指标入门,高次剩余,Miller_Rabin+Pollard_Rho)

    注:转载本文须标明出处. 原文链接https://www.cnblogs.com/zhouzhendong/p/Number-theory.html 数论算法 剩余系相关 学习笔记 (基础回顾,(ex ...

  8. BSGS算法学习笔记

    从这里开始 离散对数和BSGS算法 扩展BSGS算法 离散对数和BSGS算法 设$x$是最小的非负整数使得$a^{x}\equiv b\ \ \ \pmod{m}$,则$x$是$b$以$a$为底的离散 ...

  9. Discrete Logging(POJ2417 + BSGS)

    题目链接:http://poj.org/problem?id=2417 题目: 题意: 求一个最小的x满足a^x==b(mod p),p为质数. 思路: BSGS板子题,推荐一篇好的BSGS和扩展BS ...

随机推荐

  1. WPF时间长度自定义选择控件TimeSpanBox

    以下控件采用https://www.cnblogs.com/cssmystyle/archive/2011/01/17/1937361.html部分代码 以下控件采用https://www.cnblo ...

  2. 【剑指 Offer】12.矩阵中的路径

    题目描述 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径.路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左.右.上.下移动一格. 如果一条路径经过了矩阵的某一格,那么 ...

  3. 日常采坑:.NET Core SDK版本问题

    1..NetCore SDK版本问题 .NetCore3.1 webapi 部署linux,遇到一个坑,开启的目录浏览功能失效,几番尝试发现是版本问题.本地sdk版本与linux安装的sdk版本不对应 ...

  4. SQL Server解惑——查询条件IN中能否使用变量

    在SQL Server的查询条件中,能否在IN里面使用变量呢? 如果可以的话,有没有需要注意的地方或一些限制呢?在回答这个问题前,我们先来看看这个例子: IF EXISTS (SELECT 1 FRO ...

  5. 【Problem】前端项目运行:Module build failed:Error Node Sass does not yet support my current environmen

    我在运行renren-fast-vue前端项目时,安装完依赖cnpm install 启动服务npm run dev 出现问题. Module build failed: Error: Node Sa ...

  6. Tippy.js - 免费开源且高度可定制的气泡提示独立组件

    推荐一个非常优秀的 web 气泡提示独立UI组件. 介绍 Tippy.js 是一款用于Web的完整工具提示,弹出菜单,下拉菜单和菜单解决方案.适用于鼠标,键盘和触摸输入. 特点 超轻量的纯 javas ...

  7. AmoebaNet:经费在燃烧,谷歌提出基于aging evolution的神经网络搜索 | AAAI 2019

    论文提出aging evolution,一个锦标赛选择的变种来优化进化算法,在NASNet搜索空间上,对比强化学习和随机搜索,该算法足够简洁,而且能够更快地搜索到更高质量的模型,论文搜索出的Amoeb ...

  8. 【一天一个知识点系列】- Http之状态码

    状态码 简介 HTTP 状态码负责表示客户端 HTTP 请求的返回结果. 标记服务器端的处理是否正常. 通知出现的错误等工作 作用及类别 作用:状态码告知从服务器端返回的请求结果 状态码的类别 注意: ...

  9. pytest:conftest.py文件

    一.fixture scope 为session 级别是可以跨 .py模块调用的,也就是当我们有多个 .py文件的用例时,如果多个用例只需调用一次fixture,可以将scope='session', ...

  10. YARN运行流程