BSGS

BSGS,全称叫 BabyStepGiantStep,也就是大步小步

其实还是比较暴力的

它可以\(O(\sqrt p)\)的复杂度内解出:

\[a^x\equiv n\pmod p,\gcd(a,p)=1
\]

中\(x\)的值

如果\(\gcd(a,p)\neq 1\)就要用到 exBSGS 了

我们考虑令\(x=im-k,0\le k<m\)

那么原式变为

\[a^{im-k}\equiv n\pmod p
\]

\[a^{im}\equiv na^k\pmod p
\]

那么,我肯可以枚举\(k\in[0,m)\),计算出\(na^k\bmod p\)的值,然后把对应的\(k\)存下来

可以用map或 hash,用map会多一个\(\log\)

然后,再枚举\(i\in[0,\lceil\frac{p}{m}\rceil]\),计算出\(a^{im}\bmod p\)

然后看一看之前有没有一个\(k\),使得\(na^k\equiv a^{im}\pmod p\),且\(im>=k\)

如果有,那么答案肯定就是\(im-k\)

如果一直没找到,那么就无解

复杂度是\(O(\max(m,\frac{p}{m} ))\),显然,让\(m=\lceil \sqrt p \rceil\)时最优,即为\(O(\sqrt p)\)

但是,我们考虑的只是\(x\in[1,p]\)的情况,那为什么要找的这个\(x\)一定满足这样的性质呢?

首先\(\gcd(a,p)=1\),满足欧拉定理的条件,也就是会有\(a^{\varphi(p)}\equiv 1\pmod p\Rightarrow a^{q\varphi(p)}\equiv 1\pmod p,q\in\mathbb{N^*}\)

那么,\(k\bmod \varphi(p)=k-q\varphi(p)<\varphi(p)<p\)

则\(a^{k\bmod \varphi(p)}=\dfrac{a^k}{a^{q\varphi(p)}}\)

又由于那个分母在\(\bmod p\)中同余于\(1\)

所以\(a^{k\bmod \varphi(p)}\equiv a^k\pmod p\)

则可以得知,要求的最小的\(x\),如果有解,一定满足\(x<\varphi(p)<p\)

模板题:P3846 [TJOI2007] 可爱的质数

这题保证了\(a,n<p\),所以不需要一些奇奇怪怪的特判

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<iostream>
  4. #include<cmath>
  5. #include<iomanip>
  6. #include<cstring>
  7. #include<map>
  8. #define reg register
  9. #define EN std::puts("")
  10. #define LL long long
  11. inline int read(){
  12. register int x=0;register int y=1;
  13. register char c=std::getchar();
  14. while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
  15. while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
  16. return y?x:-x;
  17. }
  18. std::map<int,int>map;
  19. inline int power(int a,int b,int p){
  20. int ret=1;
  21. while(b){
  22. if(b&1) ret=1ll*ret*a%p;
  23. b>>=1;a=1ll*a*a%p;
  24. }
  25. return ret;
  26. }
  27. inline int BSGS(int a,int n,int p){
  28. reg int m=std::ceil(std::sqrt(p));
  29. for(reg int i=0,s=n;i<m;i++,s=1ll*s*a%p) map[s]=i;
  30. for(reg int i=0,tmp=power(a,m,p),s=1;i<=m;i++,s=1ll*s*tmp%p)
  31. if(map.find(s)!=map.end())
  32. if(i*m>=map[s]) return i*m-map[s];
  33. return -1;
  34. }
  35. int main(){
  36. int p=read(),a=read(),n=read();
  37. LL ans=BSGS(a,n,p);
  38. ans==-1?std::puts("no solution"):std::printf("%lld",ans);
  39. return 0;
  40. }

exBSGS

用于处理上面哪个问题\(\gcd(a,p)\neq 1\)的情况

有些细节稍显恶心(其实还好

首先,原来那个同余方程可以等价的写成:

\[a^x+kp=n
\]

设\(\gcd(a,p)=d\)

由于斐蜀定理,这个式子有解的充要条件是\(d\mid n\),否则直接返回无解

那么上面的式子就是:

\[a^{x-1}\cdot \frac{a}{d}+k\cdot\frac{p}{d}=\frac{n}{d}
\]

此时,\(a^{x-1}\rightarrow a^x,\frac{p}{d}\rightarrow p,\frac{n}{d}\rightarrow n\)

那么一直递归,直到\(\gcd(a,p)=1\)

所以此时设一共递归了\(cnt\)次,这所有次递归的\(d\)的乘积是\(d\)(用一个字母说起来省事

原式就是

\[a^{x-cnt}\cdot \frac{a^{cnt}}{d}\equiv \frac{n}{d}\pmod {\frac{p}{d}}
\]

那么我们就用\(a'=a,n'=\frac{n}{d},p'=\frac{p}{d}\)来跑一次 BSGS 就行了

当然,答案还要再加上\(cnt\)

而且,还有一个\(\dfrac{a^{cnt}}{d}\)的系数要乘上,具体对应代码中的变量ad,要传参到 BSGS 的函数里

模板题:SP3105 MOD - Power Modulo InvertedP4195 【模板】exBSGS

还是双倍经验,但是这个不保证\(a,n<p\),所以要先模一下,然后判断一下是不是等于\(0\),具体看代码

而且这个还卡常,必须要用unordered_map,它的内部实现是哈希表,而map是红黑树,前者构建好像稍慢,但是查询快,适合这个题

话说我写这题的时候听说卡常,然后T了以后猛卡常数,结果后来发现是写法错了,于是就对着错误的程序卡了一晚上常直至自闭

不过是 c++11 的东西,noip可能不能用,编译时要加上-std=c++11

当然写 hash 也可以,但我不太会/kk

  1. #include<cstdio>
  2. #include<map>
  3. #include<algorithm>
  4. #include<iostream>
  5. #include<cmath>
  6. #include<iomanip>
  7. #include<cstring>
  8. #include<unordered_map>
  9. #define reg register
  10. #define EN std::puts("")
  11. #define LL long long
  12. inline int read(){
  13. register int x=0;register int y=1;
  14. register char c=std::getchar();
  15. while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
  16. while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
  17. return y?x:-x;
  18. }
  19. std::unordered_map<int,int>map;
  20. int gcd(int a,int b){return b?gcd(b,a%b):a;}
  21. inline int BSGS(int a,int n,int p,int ad){
  22. map.clear();
  23. reg int m=std::ceil(std::sqrt(p));
  24. reg int s=1;
  25. for(reg int i=0;i<m;i++,s=1ll*s*a%p) map[1ll*s*n%p]=i;
  26. for(reg int i=0,tmp=s,s=ad;i<=m;i++,s=1ll*s*tmp%p)
  27. if(map.find(s)!=map.end())
  28. if(1ll*i*m-map[s]>=0) return 1ll*i*m-map[s];
  29. return -1;
  30. }
  31. inline int exBSGS(int a,int n,int p){
  32. a%=p;n%=p;
  33. if(n==1||p==1) return 0;
  34. reg int cnt=0;
  35. reg int d,ad=1;
  36. while((d=gcd(a,p))^1){
  37. if(n%d) return -1;
  38. cnt++;n/=d;p/=d;
  39. ad=(1ll*ad*a/d)%p;
  40. if(ad==n) return cnt;
  41. }
  42. // std::printf("a: %d n: %d p: %d ad:%d\n",a,n,p,ad);
  43. LL ans=BSGS(a,n,p,ad);
  44. if(ans==-1) return -1;
  45. return ans+cnt;
  46. }
  47. signed main(){
  48. int a=read(),p=read(),n=read();
  49. while(a||p||n){
  50. int ans=exBSGS(a,n,p);
  51. if(~ans) std::printf("%d\n",ans);
  52. else std::puts("No Solution");
  53. a=read();p=read();n=read();
  54. }
  55. return 0;
  56. }

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及其扩展

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

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

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

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

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

  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. Linux 磁盘管理篇,连接文件

    连接文件分为两种 1.像Window类似的快捷方式的文件 2.通过文件系统的inode来产生新的文件名而不是新文件(硬连接) 创建连接文件            ln 创建连接文件的快捷方式      ...

  2. 28.2 api-- System (gc、arraycopy、exit)

    /* * System:包含一些有用的类字段和方法.它不能被实例化 * static void arraycopy(Object src, int srcPos, Object dest, int d ...

  3. 挑战全网最幽默的Vuex系列教程:第一讲 Vuex到底是什么鬼

    先说两句 官方已经有教程了,为什么还要写这个教程呢?说实话,还真不是我闲着蛋疼,官方的教程真的是太官方了,对于刚入门 Vuex 的童鞋来说,想必看官方的教程,很多地方就如同看圣经一样,比如「欧玛尼玛尼 ...

  4. 使用基于vuecli创建的目录推送到指定远程分支

    笔者使用vuecli创建项目目录以后,在想将该目录提交到远程仓库时发现行不通,在忙活了一下午以后写下此文 1.github上新建一空分支,然后克隆该分支地址:  https://github.com/ ...

  5. 数据结构和算法(Golang实现)(10)基础知识-算法复杂度主方法

    算法复杂度主方法 有时候,我们要评估一个算法的复杂度,但是算法被分散为几个递归的子问题,这样评估起来很难,有一个数学公式可以很快地评估出来. 一.复杂度主方法 主方法,也可以叫主定理.对于那些用分治法 ...

  6. break与continue用法注意事项

    break 中断循环执行,跳出循环 注意,break只能中断自己所在的循环,一般用在内层循环,但是不能中断外层循环中的代码. continue 跳到循环的下一轮继续执行,结束自己所在循环体代码,继续自 ...

  7. 带你五分钟了解python的函数式编程与闭包

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:梁唐 PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行 ...

  8. 三分钟教会你Python数据分析—数据导入,小白基础入门必看内容

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:小白 PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行 ...

  9. 简单网络编程如何用python来实现

    对于网络编程,通信模式是后台必备技能,先用最基础代码实现,理解一些 API 的含义,在深入学习. 总是有读者问过我关于 Python 后台开发相关,如果想走 Python 后台方向,对于 Python ...

  10. E - Farthest Nodes in a Tree

    Given a tree (a connected graph with no cycles), you have to find the farthest nodes in the tree. Th ...