文章目录

  • 原根
  • BSGS大步小步算法
  • 扩展BSGS

原根

如果两个整数a,ba,ba,b互质,则有aϕ(b)%b=1a^{\phi(b)}\%b=1aϕ(b)%b=1

定义模bbb意义下的aaa的阶为使ad%b=1a^d\%b=1ad%b=1的最小正整数ddd

显然,模bbb的阶d∣ϕ(b)d|\phi(b)d∣ϕ(b)

如果模bbb意义下aaa的阶为ϕ(b)\phi(b)ϕ(b),则称aaa为bbb的原根

欧拉证明了(我证明不了)

模bbb存在原根的充要条件为:b=2,4,pn,2pnb=2,4,p^n,2p^nb=2,4,pn,2pn,其中ppp为奇素数,n∈N∗n∈N^*n∈N∗

当模bbb有原根时,其原根个数为ϕ(ϕ(b))\phi(\phi(b))ϕ(ϕ(b))

那么如何求一个数的原根?

首先判断它是否有原根

如果有,一般最小原根都很小,可以选择美丽的暴力

预处理出ϕ(b)\phi(b)ϕ(b)的所有因子,存放在数组DDD中

在[2,ϕ(b))[2,\phi(b))[2,ϕ(b))区间中,从小到大米枚举变量iii

如果存在j∈Dj∈Dj∈D,使得iϕ(b)j%b=1i^{\frac{\phi(b)}{j}}\%b=1ijϕ(b)​%b=1,则iii不是原根,否则iii是原根

为什么这样是正确的呢?

因为如果存在一个数1≤x<ϕ(b)1\le x<\phi(b)1≤x<ϕ(b),使得ix%b=1i^x\%b=1ix%b=1

则x∣ϕ(b)x|\phi(b)x∣ϕ(b),并且一定存在一个ϕ(b)\phi(b)ϕ(b)的质因子jjj,使得x∣ϕ(b)jx|\frac{\phi(b)}{j}x∣jϕ(b)​


BSGS大步小步算法

BSGS是用来解决离散对数问题的

即ax≡b(modp)a^x\equiv b\ (mod\ \ p)ax≡b (mod  p),其中a,b,pa,b,pa,b,p已知,且(a,p)=1(a,p)=1(a,p)=1,求xxx

因为aϕ(p)≡1(modp),ϕ(p)<pa^{\phi(p)}\equiv 1\ (mod\ \ p),\phi(p)<paϕ(p)≡1 (mod  p),ϕ(p)<p

所以可以采取枚举法,在O(p)O(p)O(p)的时间复杂度求出xxx

而BSGSBSGSBSGS可以在O(p)O(\sqrt{p})O(p​)的时间复杂度内求出xxx

令m=⌈p⌉,r=xmodmm=\lceil \sqrt{p} \rceil,r=x\mod mm=⌈p​⌉,r=xmodm,则x=k∗m+rx=k*m+rx=k∗m+r,其中0≤k<m,0≤r<k0\le k<m,0\le r<k0≤k<m,0≤r<k,有
ak∗m+r≡b(modp)a^{k*m+r}\equiv b\ \ (mod\ \ p)ak∗m+r≡b  (mod  p)

因为(a,p)=1(a,p)=1(a,p)=1,方程两边同乘a−ra^{-r}a−r

ak∗m≡b∗a−r(modp)a^{k*m}\equiv b*a^{-r}\ \ (mod\ \ p)ak∗m≡b∗a−r  (mod  p)

对于0≤i<r0\le i<r0≤i<r,求出所有的b∗a−1modpb*a^{-1}\mod\ \ pb∗a−1mod  p,将其值以及iii存入mapmapmap

然后再求左边的aj∗mmodp,(0≤j<k)a^{j*m}\mod p,(0\le j<k)aj∗mmodp,(0≤j<k),并在mapmapmap里寻找是否出现过相同的值

如果有,代表着同余,已经找到了答案,如果没有则是无解

然而。。。

可以稍微转变一下算法过程,避免求逆元的操作

x=k∗m+r=(k+1)∗m−m+r=(k+1)∗m−(m−r)x=k*m+r=(k+1)*m-m+r=(k+1)*m-(m-r)x=k∗m+r=(k+1)∗m−m+r=(k+1)∗m−(m−r)
因为有 r<mr<mr<m 所以考虑换一种方式枚举 r←m−rr\leftarrow m-rr←m−r
⇒x=k∗m−r,(1≤k≤m,0≤r<m)\Rightarrow x=k*m-r,(1\le k\le m,0\le r<m)⇒x=k∗m−r,(1≤k≤m,0≤r<m)
则ak∗m−r≡b(modp)a^{k*m-r}\equiv b\ \ (\mod p)ak∗m−r≡b  (modp)
两边同时乘以ara^rar
ak∗m≡b∗ar(modp)a^{k*m}\equiv b*a^r\ \ (\mod p)ak∗m≡b∗ar  (modp)
先求出右边所有的b∗ai(modp)(1≤i≤m)b*a^i(\mod p)(1\le i\le m)b∗ai(modp)(1≤i≤m)保存在mapmapmap中

然后再求左边的aj∗mmodpa^{j*m}\mod\ paj∗mmod p,并在mapmapmap中查找是否出现过

如果出现过,左边枚举的是jjj,右边枚举的是iii,则答案为x=j∗m−ix=j*m-ix=j∗m−i,这样就避免了求逆元的操作,却仍然用到了逆元

因为推导必须是等价推导,只有当(a,p)=1(a,p)=1(a,p)=1,即ara^rar逆元存在时,才可以大胆两边同乘ara^rar等价,因为如果(a,p)≠1(a,p)≠1(a,p)​=1,式子倒推不回去

#include <map>
#include <cmath>
#include <cstdio>
using namespace std;
#define int long long
map < int, int > mp;
int a, mod, r;int bsgs() {mp.clear();int m = ceil( sqrt( mod ) );int tmp = 1;for( int i = 1;i <= m;i ++ ) {tmp = tmp * a % mod;mp[tmp * r % mod] = i;}int res = 1;for( int i = 1;i <= m;i ++ ) {res = res * tmp % mod;if( mp[res] ) return m * i - mp[res];}return -1;
}signed main() {int ans;while( ~ scanf( "%lld %lld %lld", &mod, &a, &r ) ) {r %= mod, a %= mod;if( r == 1 ) ans = 0;else if( ! a ) {if( r ) ans = -1;else ans = 1;}else ans = bsgs();if( ans == -1 ) printf( "no solution\n" );else printf( "%lld\n", ans );}return 0;
}

扩展BSGS

对于ax≡b(modp)a^x\equiv b(\mod p)ax≡b(modp)

如果(a,p)>1(a,p)>1(a,p)>1,则无法直接套用BSGS,此时就要用到扩展BSGS

将要求解的式子变形
ax+k∗p=ba^x+k*p=bax+k∗p=b
设(a,p)=g(a,p)=g(a,p)=g,若bbb不是ggg的倍数,则方程无解

不过有一个例外b=1,x=0b=1,x=0b=1,x=0,这个情况特判即可

式子左右两边除以ggg
ax−1ag+kpg=bga^{x-1}\frac{a}{g}+k\frac{p}{g}=\frac{b}{g}ax−1ga​+kgp​=gb​
令a′=ag,p′=pg,b′=bga'=\frac{a}{g},p'=\frac{p}{g},b'=\frac{b}{g}a′=ga​,p′=gp​,b′=gb​
ax−1a′+kp′=b′a^{x-1}a'+kp'=b'ax−1a′+kp′=b′
若a,p′a,p'a,p′仍然不互质,则继续以上操作找出a,p′a,p'a,p′的最大公约数g′g'g′

最新式子两边继续除以g′g'g′,直到(a,p′)=1(a,p')=1(a,p′)=1为止

在此过程中,假设取出来了cntcntcnt个aaa,出去公约数后剩下的乘积为a′a'a′

此时(a′,p′)=1(a',p')=1(a′,p′)=1,于是可以转化为ax−cnta′≡b(modp)⇔ax−cnt≡b′(a′)−1(modp)a^{x-cnt}a'\equiv b\pmod p \Leftrightarrow a^{x-cnt}\equiv b'(a')^{-1}\pmod pax−cnta′≡b(modp)⇔ax−cnt≡b′(a′)−1(modp)
其中cntcntcnt表示两边除以最大公约数ggg的次数

此处右边有逆元,为了避免求逆元,将a′a'a′保留在左边

在BSGS枚举左边时,初始值设为a′a'a′即可

如果在除以ggg的过程中,发现b′(a′)−1=1⇔b′≡a′⇒x−cnt=0⇒x=cntb'(a')^{-1}=1\Leftrightarrow b'\equiv a'\Rightarrow x-cnt=0\Rightarrow x=cntb′(a′)−1=1⇔b′≡a′⇒x−cnt=0⇒x=cnt

接下来,直接套用基础BSGS即可,记得最后的答案不要忘记加上cntcntcnt哟(^U^)ノ~YO

#include <map>
#include <cmath>
#include <cstdio>
using namespace std;
#define int long long
map < int, int > mp;
int a, mod, r;int gcd( int x, int y ) {if( ! y ) return x;else return gcd( y, x % y );
}int qkpow( int x, int y, int mod ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans;
}int exbsgs() {if( r == 1 ) return 0;int cnt = 0, tmp = 1, d;while( 1 ) {d = gcd( a, mod );if( d == 1 ) break;if( r % d ) return -1;r /= d, mod /= d;tmp = tmp * ( a / d ) % mod;++ cnt;if( tmp == r ) return cnt;}mp.clear();int res = r;mp[r] = 0;int m = ceil( sqrt( 1.0 * mod ) );for( int i = 1;i <= m;i ++ ) {res = res * a % mod;mp[res] = i;}int temp = qkpow( a, m, mod );res = tmp;for( int i = 1;i <= m;i ++ ) {res = res * temp % mod;if( mp.count( res ) )return i * m - mp[res] + cnt;}return -1;
}signed main() {while( ~ scanf( "%lld %lld %lld", &a, &mod, &r ) ) {if( ! a && ! mod && ! r ) return 0;int ans = exbsgs();if( ans == -1 ) printf( "No Solution\n" );else printf( "%lld\n", ans );}return 0;
}

【学习笔记】原根 / BSGS / 扩展BSGS证明及模板相关推荐

  1. es6学习笔记-字符串的扩展_v1.0_byKL

    es6学习笔记-字符串的扩展_v1.0 字符的Unicode表示法 JavaScript 允许使用uxxxx的形式表示一个字符,但在 ES6 之前,单个码点仅支持u0000到uFFFF,超出该范围的必 ...

  2. ASP.Net MVC开发基础学习笔记(5):区域、模板页与WebAPI初步

    http://blog.jobbole.com/85008/ ASP.Net MVC开发基础学习笔记(5):区域.模板页与WebAPI初步 2015/03/17 · IT技术 · .Net, Asp. ...

  3. BSGS扩展BSGS

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

  4. 学习笔记(符号扩展指令:SXTB和SXTH)

    前言 这些笔记主要是记录自己在学习CM3汇编中的一些问题(因为我们老师上stm32的嵌入式课是从基础汇编开始讲的,CM3汇编在网上能查到的例子讲解有点少,哭!),其中可能借鉴过网上一些大佬的文章,如果 ...

  5. vs2010 学习Silverlight学习笔记(7):控件样式与模板

    概要: 终于知道Silverlight--App.xaml是干什么用的了,不仅可以用来封装样式(类似css),还可以制定控件模版...好强大的功能啊. 封装: 继续学习<一步一步学Silverl ...

  6. SpringBoot学习笔记【part12】Web开发——Thymeleaf模板引擎

    SpringBoot 学习笔记 Part12 1. thymeleaf简介 SpringBoot默认不支持 JSP,需要引入第三方模板引擎技术实现页面渲染. Thymeleaf is a modern ...

  7. Unity学习笔记--Extension Method 扩展方法

    引言 最近跟着麦克学习Unity的时候,学习到了类的扩展方法.比如你现在有一个已有的类,你想给它加一个方法,当然如果是你自己写的类可以直接在这个方法里面写,但是如果是Unity自带的类,我们不可能直接 ...

  8. Kotlin学习笔记(五) 扩展函数 扩展属性

    2019独角兽企业重金招聘Python工程师标准>>> 扩展函数和属性可以定义在对应的类中和kotlin文件中; 1.扩展函数 1.扩展函数可以由对象直接调用,在扩展函数中,用thi ...

  9. 【学习笔记】Sperner定理及其证明

    额,最近看到了一个十分有趣的定理--Sperner定理.其实这个定理在OI中没什么用处,因此我都没把这篇文章放到我的OI标签里(不知道在MO中是否有用?)但是觉得它很有趣于是就过来写一下. 由于博主太 ...

最新文章

  1. self.navigationController push到指定控制器
  2. 聊聊storm的stream的分流与合并
  3. 64位ubuntu安装WPS
  4. 科普 | 5G基站功耗,到底有多可怕?
  5. centos下crontab的使用
  6. 如何使用和自定义Win11快速设置菜单
  7. Python多态、鸭子类型
  8. 转:为 setuptools 开路搭桥
  9. 环境搭建:mobaxterm连接本地虚拟机
  10. 190623每日一句
  11. Rust: 用于量化研究的尝试探讨
  12. Deecamp20 项目提交【如何用pcdet(second)跑自己的数据】
  13. 论述:企业如何做好网络营销推广
  14. api系列聚美优品的知识点
  15. 采购订单税码检查增强(badi)
  16. 机器学习(1)——Python数据处理与绘图
  17. AdTech被称为黄金赛道,为什么2020年翻倍股频出?
  18. Java正则表达式(详解)
  19. Flutter返回页面时刷新页面
  20. primer练习11.14

热门文章

  1. oracle中触发器只能用于表吗,Oracle触发器的分类和使用
  2. php网页连mysql_php - 如何在单个网页上连接多个MySQL数据库?
  3. mac mysql 移动硬盘_MAC一些高能过程记录(一些没必要的坑)
  4. 通信开源linux,Linux环境进程间通信
  5. redis session java获取attribute_redis里的数据结构
  6. golang 切片 接口_Golang语言常用关键字之 make 和 new
  7. android虚线边框_Android实现代码画虚线边框背景效果
  8. listview在java中的使用_我的Android开发之路——ListView的使用
  9. [SpringSecurity]web权限方案_用户认证_自定义用户登录页面
  10. [计组]寄存器的基本含义