BSGS算法及其扩展
bsgs算法:
我们在逆元里曾经讲到过如何用殴几里得求一个同余方程的整数解。而 $ bsgs $ 就是用来求一个指数同余方程的最小整数解的:也就是对于 $ a^x\equiv b \mod p $ 我们可以用 $ bsgs $ 在 $ O(\sqrt n) $ 的复杂度内求出关于 $ x $ 的最小正整数解。(前提是 $ p $ 为质数)
$ a^x\equiv b \mod p $
我们可以知道如果我们的模数p是一个质数,我们将同余式的右边以逆元的形式乘到左边来,根据殴拉定理(因为p是质数,所以a,p互质)则我们的x一定有一个小于p的正整数解!(当然,我们还要特判一下a是p倍数这一情况)。如果我们用穷举法来求这一个x最小是多少,复杂度显然不能接受,而 $ bsgs $ 就是做到了用空间来换取时间,对这个穷举进行一个改进。
其实这里 $ bsgs $ 的用空间换时间,和我们搜索用的双向搜是一个原理的。它充分利用了同余的性质,我们设m为 $ \sqrt a $ 向上取整,然后原式左边就变成了 $ ax=(am)^i\times a^j _{x=i+j} $ 这样我们第一步从小到大枚举i是多少,然后算出 $ (am)i $ ,然后根据同余方程我们就可以知道我们还需要的 $ a^j $ 是多少。于是第二步我们就可以先预处理出所有 $ a^j $ 然后存到hash表里,然后每算一个 $ (am)i $ 我们就在hash表中查看有没有对应的 $ a^j $ 存在(存hash的同时要保留 $ j $ 的值).这样我们整个算法的复杂度就是 $ O(\sqrt n) $ 了!
$ code: $
inline ll bsgs(int x,ll y,ll p){
int z=pow(p,0.5)+1;
ll sx=1,sy=1;
for(rg i=0;i<z;++i,sx=ksc(sx,x,p))
ha1(i,ksc(sx,y,p));//先把所有的a^j存入hash表
sy=1;
for(rg i=0;i<=z;++i,sy=ksc(sy,sx,p)){//可能用到快速乘
for(rg j=tou[sy%376637];j;j=b[j].p)//查看hash表中是否有相应的a^j
if(sy==b[j].y)return (ll)i*z-b[j].x;
}return p-1;//这句话其实可以省。
}
例题:

$ solution $ :
这道题还是比较裸的,我们可以讲题目中的同余方程左右同乘9再加1,得到: $ 10^x\equiv k\times 9+1\mod m $ 。这样就直接变成了一道板子题了(不过bsgs的题目向来是要用到快速乘的):
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define lb long double
#define ll long long
#define db double
#define rg register int
using namespace std;
struct su{
int p,x;
ll y;
}b[376637];
int top;
ll k,m;
int tou[376637];
inline ll qr(){//快读
char ch;
while((ch=getchar())<'0'||ch>'9');
ll res=ch^48;
while((ch=getchar())>='0'&&ch<='9')
res=res*10+(ch^48);
return res;
}
inline ll ksc(ll x,ll y,ll p){//快速乘
return (x*y-(ll)((lb)x/p*y)*p+p)%p;
}
inline void ha1(int x,ll y){//y用链式前向星来hash
b[++top].x=x; b[top].y=y; y%=376637;
b[top].p=tou[y]; tou[y]=top;
}
inline ll bsgs(int x,ll y,ll p){//快速乘
int z=pow(p,0.5)+1;
ll sx=1,sy=1;
for(rg i=0;i<z;++i,sx=ksc(sx,x,p))
ha1(i,ksc(sx,y,p));
sy=sx;
for(rg i=1;i<=z;++i,sy=ksc(sy,sx,p)){
for(rg j=tou[sy%376637];j;j=b[j].p)
if(sy==b[j].y)return (ll)i*z-b[j].x;
}return p-1;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
k=qr(); m=qr(); k=(k*9+1)%m;//稍稍处理一下
printf("%lld\n",bsgs(10,k,m));
return 0;
}
$ BSGS $ 算法的扩展:
上面我们有讲过一般的 $ BSGS $ 算法是有前提条件的(我们的p必须是素数)。但是当我们的p不是素数的时候我们也是可以用 $ BSGS $ 求出来的,只是要先做处理。因为同余具有这样一条神奇的性质(同除性): $ a\equiv b \mod m \quad ->\quad d=gcd(a,b,p) \quad-> \quad \frac{a}{d} \equiv \frac{b}{d}\mod \frac{m}{d} $
根据这条性质,我们可以将a,p 取gcd 。而在扩展欧几里得解一次同余方程中我们说过,如果要有一组整数解,冲要条件就是我们的gcd(a,p)可以整除b!所以如果我们在BSGS中给三者用同除时如果b不能为整数了则无解!对这个进行特判后我们就可以一直同除(注意我们的同余式左边可以是多个a的乘积1)直到 $ a^x $ 与 $ p $ 互质。这时我们就可以再次 $ BSGS $ 来求解了(注意我们此时只保证 $ a^x $ 与 $ p $ 互质,而不是p为素数,所以可能无解!)
$ code $ :
inline int bsgs(int x,int y,int p,int ex){
int z=sqrt(p)+1; ll sx=1,sy;
for(rg i=0;i<z;++i)
ha(i,sx*y%p),sx=sx*x%p;
sy=sx;
for(rg i=1;i<=z;++i,sy=sy*sx%p)
for(rg j=tou[sy%72727];j;j=b[j].p)
if(b[j].y==sy)return i*z-b[j].x;
return -1;//可能无解
}
例题:
洛谷 P4195 【模板】exBSGS/Spoj3105 Mod

这确确实实就是道模板,不过是多组数据,所以我们用手写hash防被卡:
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define lb long double
#define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int
using namespace std;
struct su{
int x,y,p;
}b[72727];
int n,m,mod,ans;
int top,tou[72727];
inline int qr(){
char ch;
while((ch=getchar())<'0'||ch>'9');
int res=ch^48;
while((ch=getchar())>='0'&&ch<='9')
res=res*10+(ch^48);
return res;
}
inline int gcd(int x,int y){
int z;
while(y){z=x,x=y,y=z%y;}
return x;
}
inline int ksm(ll x,int y,int p){
int res=1;
while(y){
if(y&1)res=res*x%p;
x=x*x%p; y>>=1;
}return res;
}
inline void ha(int x,int y){
b[++top].x=x; b[top].y=y; y%=72727;
b[top].p=tou[y]; tou[y]=top;
}
inline int bsgs(int x,int y,int p,int ex){
int z=sqrt(p)+1; ll sx=1,sy;
for(rg i=0;i<z;++i)
ha(i,sx*y%p),sx=sx*x%p;
sy=sx*ex%p;
for(rg i=1;i<=z;++i,sy=sy*sx%p)
for(rg j=tou[sy%72727];j;j=b[j].p)
if(b[j].y==sy)return i*z-b[j].x;
return -1;
}
inline int ex_bsgs(int x,int y,int p){
if(y==1)return 0;
ll c=1,z=x,d; int k=0;
while(1){
d=gcd(x,p);
if(d==1)break;
if(y%d)return -1;
++k; c=c*(x/d)%p;
y/=d; p/=d;
if(c==y)return k;
}z=bsgs(x,y,p,c);
return z==-1?z:z+k;
}
signed main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
while(n=qr(),mod=qr(),m=qr(),n){top=0;
for(rg i=0;i<72727;++i)tou[i]=0;
ans=ex_bsgs(n%mod,m%mod,mod);
if(ans!=-1)printf("%d\n",ans);
else puts("No Solution");
}
return 0;
}
BSGS算法及其扩展的更多相关文章
- BSGS算法及扩展
BSGS算法 \(Baby Step Giant Step\)算法,即大步小步算法,缩写为\(BSGS\) 拔山盖世算法 它是用来解决这样一类问题 \(y^x = z (mod\ p)\),给定\(y ...
- BSGS算法学习笔记
从这里开始 离散对数和BSGS算法 扩展BSGS算法 离散对数和BSGS算法 设$x$是最小的非负整数使得$a^{x}\equiv b\ \ \ \pmod{m}$,则$x$是$b$以$a$为底的离散 ...
- BSGS算法总结
BSGS算法总结 \(BSGS\)算法(Baby Step Giant Step),即大步小步算法,用于解决这样一个问题: 求\(y^x\equiv z\ (mod\ p)\)的最小正整数解. 前提条 ...
- BSGS算法+逆元 POJ 2417 Discrete Logging
POJ 2417 Discrete Logging Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 4860 Accept ...
- BSGS算法解析
前置芝士: 1.快速幂(用于求一个数的幂次方) 2.STL里的map(快速查找) 详解 BSGS 算法适用于解决高次同余方程 \(a^x\equiv b (mod p)\) 由费马小定理可得 x &l ...
- 【codevs 1565】【SDOI 2011】计算器 快速幂+拓展欧几里得+BSGS算法
BSGS算法是meet in the middle思想的一种应用,参考Yveh的博客我学会了BSGS的模版和hash表模板,,, 现在才会hash是不是太弱了,,, #include<cmath ...
- bzoj2242: [SDOI2011]计算器 && BSGS 算法
BSGS算法 给定y.z.p,计算满足yx mod p=z的最小非负整数x.p为质数(没法写数学公式,以下内容用心去感受吧) 设 x = i*m + j. 则 y^(j)≡z∗y^(-i*m)) (m ...
- 浅谈Manacher算法与扩展KMP之间的联系
首先,在谈到Manacher算法之前,我们先来看一个小问题:给定一个字符串S,求该字符串的最长回文子串的长度.对于该问题的求解.网上解法颇多.时间复杂度也不尽同样,这里列述几种常见的解法. 解法一 ...
- [BSGS算法]纯水斐波那契数列
学弟在OJ上加了道"非水斐波那契数列",求斐波那契第n项对1,000,000,007取模的值,n<=10^15,随便水过后我决定加一道升级版,说是升级版,其实也没什么变化,只 ...
随机推荐
- python构建bp神经网络_鸢尾花分类(一个隐藏层)__1.数据集
IDE:jupyter 目前我知道的数据集来源有两个,一个是csv数据集文件另一个是从sklearn.datasets导入 1.1 csv格式的数据集(下载地址已上传到博客园----数据集.rar) ...
- python构建bp神经网络_曲线拟合(一个隐藏层)__1.可视化数据
1.将数据写入csv文件,应该可以python代码直接实现数据集的写入,但我对文件读取这块不太熟练,等我成功了再加上,这里我直接手写将数据集写入Excel 2.然后把后缀改成.csv就可以了,利用pa ...
- python—— 写入错误UnicodeEncodeError的解决办法
在写python爬虫过程中,有时候吧结果写入到txt文件,但是会遇到UnicodeEncodeError. 错误原因—— 把文件内容,写入到文件中时,出错了. 而出错的原因其实是,python系统,在 ...
- 架构师成长之路6.1 DNS理论
点击返回架构师成长之路 架构师成长之路6.1 DNS理论 1.DNS一些基本概念 ① FQDN:Full Qualified Domain Name,完全限定域名,即每个域在全球网络都是唯 ...
- SharePoint 2013 批量导入、删除帐号
删除一个group里所有的帐号: cls ########################### # "Enter the site URL here" $SITEURL = &q ...
- uoj233/BZOJ4654/洛谷P1721 [Noi2016]国王饮水记 【dp + 斜率优化】
题目链接 uoj233 题解 下面不加证明地给出几个性质: 小于\(h[1]\)的城市一定是没用的 任何城市联通包含\(1\)且只和\(1\)联通一次 联通顺序从小到大最优 单个联通比多个一起联通要优 ...
- JAVA8给我带了什么——并行流和接口新功能
流,确定是笔者内心很向往的天堂,有他之后JAVA在处理数据就变更加的灵动.加上lambda表达不喜欢都不行.JAVA8也为流在提供另一个功能——并行流.即是有并行流,那么是不是也有顺序流.没有错.我前 ...
- A1027. Colors in Mars
People in Mars represent the colors in their computers in a similar way as the Earth people. That is ...
- 关于移动端及flex
我们知道写pc页面的时候,ui设计图是多少px,我们写网页的时候,就会写多少px,这个其实就是由pc端屏幕的物理像素,和我们设计图的css逻辑像素决定的,由于屏幕的物理像素和css逻辑像素比,刚好是1 ...
- OpenCV 无法启动此程序,因为计算机中丢失opencv_core249.dll。请尝试重新安装改程序已解决此问题
换了64位的系统,配置好之后运行之前的程序,竟然给我抛出这个错误.应该是我的opencv没有安装对吧.系统报错 无法启动此程序,因为计算机中丢失opencv_core249.dll.请尝试重新安装改程 ...