title : 离散对数与BSGS
date : 2021-8-12
tags : ACM,数论
author Linno
阶
对与m互质的整数a,我们记满足 a n ≡ 1 m o d m a^n\equiv 1\mod m an≡1modm的最小正整数n为a模m的阶,记为 δ m ( a ) \delta_m(a) δm(a)。
引理
① 若 m > 1 并 且 g c d ( a , m ) = 1 , 又 满 足 a n ≡ 1 m o d m , 那 么 δ m ( a ) ∣ n ② 由 欧 拉 定 理 和 定 理 一 得 : δ m ( a ) ∣ ϕ ( m ) ①若m>1并且gcd(a,m)=1,又满足a^n\equiv 1\mod m,那么\delta_m(a)|n\\ ②由欧拉定理和定理一得:\delta_m(a)|\phi(m) ①若m>1并且gcd(a,m)=1,又满足an≡1modm,那么δm(a)∣n②由欧拉定理和定理一得:δm(a)∣ϕ(m)
欧拉定理
若 a 与 m 互 质 , 则 a ϕ ( m ) ≡ 1 m o d m 若a与m互质,则a^{\phi(m)}\equiv1\mod m 若a与m互质,则aϕ(m)≡1modm
原根
若存在与m互质的整数g,并且g模m的阶为
ϕ
(
m
)
\phi(m)
ϕ(m),那么我们称模m有原根,并称g为模m的一个原根。
若
一
个
数
能
分
解
为
x
=
r
∗
s
,
(
r
,
s
)
=
1
,
且
r
,
s
>
2
,
那
么
x
必
定
无
原
根
若
满
足
x
=
p
k
或
者
x
=
2
∗
p
k
的
形
式
,
x
才
有
可
能
有
原
根
若一个数能分解为x=r*s,(r,s)=1,且r,s>2,那么x必定无原根\\ 若满足x=p^k或者x=2*p^k的形式,x才有可能有原根
若一个数能分解为x=r∗s,(r,s)=1,且r,s>2,那么x必定无原根若满足x=pk或者x=2∗pk的形式,x才有可能有原根
相关定理
① 一 个 正 整 数 m 有 原 根 的 充 要 条 件 是 m = 2 , 4 , p e , 2 p e , 其 中 , p 为 奇 素 数 , e 为 正 整 数 ② 每 一 个 素 数 p 都 有 ϕ ( p − 1 ) 个 原 根 , 事 实 上 , 每 一 个 正 整 数 m 都 有 ϕ ( ϕ ( m ) ) 个 原 根 。 ③ 若 g 是 m 的 一 个 原 根 , 则 g , g 2 , . . . , g ϕ ( m ) , 各 数 对 m 取 模 的 非 负 最 小 剩 余 就 算 小 于 m 且 与 m 互 质 的 ϕ ( m ) 个 数 的 一 个 排 列 。 ①一个正整数m有原根的充要条件是m=2,4,p^e,2p^e,其中,p为奇素数,e为正整数\\ ②每一个素数p都有\phi(p-1)个原根,事实上,每一个正整数m都有\phi(\phi(m))个原根。\\ ③若g是m的一个原根,则g,g^2,...,g^{\phi(m)},\\各数对m取模的非负最小剩余就算小于m且与m互质的\phi(m)个数的一个排列。 ①一个正整数m有原根的充要条件是m=2,4,pe,2pe,其中,p为奇素数,e为正整数②每一个素数p都有ϕ(p−1)个原根,事实上,每一个正整数m都有ϕ(ϕ(m))个原根。③若g是m的一个原根,则g,g2,...,gϕ(m),各数对m取模的非负最小剩余就算小于m且与m互质的ϕ(m)个数的一个排列。
原根的求法
( 1 ) 首 先 求 ϕ ( m ) 的 素 幂 分 解 式 : ϕ ( m ) = p 1 e 1 ∗ p 2 e 2 ∗ . . . ∗ p k e k 然 后 枚 举 g , 若 恒 满 足 g ϕ ( m ) p i ≠ 1 m o d m , 其 中 i = 1 , 2 , . . . , k 则 g 是 m 的 一 个 原 根 (1)首先求\phi(m)的素幂分解式:\phi(m)=p_1^{e_1}*p_2^{e_2}*...*p_k^{e_k}\\ 然后枚举g,若恒满足g^{\frac{\phi(m)}{pi}}\neq1\mod m,其中i=1,2,...,k\\则g是m的一个原根 (1)首先求ϕ(m)的素幂分解式:ϕ(m)=p1e1∗p2e2∗...∗pkek然后枚举g,若恒满足gpiϕ(m)=1modm,其中i=1,2,...,k则g是m的一个原根
离散对数
离散对数是一种再整数中基于同余运算和原根的对数运算。
当
模
m
有
原
根
时
,
设
G
为
模
m
的
一
个
原
根
,
则
当
:
x
≡
G
k
m
o
d
k
时
,
l
o
g
G
(
x
)
≡
k
m
o
d
ϕ
(
m
)
此
处
的
l
o
g
G
(
x
)
是
x
以
整
数
G
为
底
模
ϕ
(
m
)
的
离
散
对
数
值
。
当模m有原根时,设G为模m的一个原根,\\ 则当:x\equiv G^k \mod k时,log_G(x)\equiv k \mod \phi(m)\\ 此处的log_G(x)是x以整数G为底模\phi(m)的离散对数值。
当模m有原根时,设G为模m的一个原根,则当:x≡Gkmodk时,logG(x)≡kmodϕ(m)此处的logG(x)是x以整数G为底模ϕ(m)的离散对数值。
BSGS
Baby-Step-Giant-Step及其拓展算法(Extended BSGS)是用来求解 A x ≡ B m o d C ( 0 ≤ x < C ) A^x\equiv B\mod C(0\le x<C) Ax≡BmodC(0≤x<C)类型问题(高次同余方程)的算法,以空间换时间,是对穷举法的一个改进。
穷举法
由费马小定理得 如果方程有解,那么一定在循环节[0,C-1]之中(费马小定理),只需要在循环节中枚举x就可以求出方程的解。(p很大的时候就会爆)
基础BSGS
只能解决C为素数的情况。
设
m
=
C
上
取
整
,
x
=
i
∗
m
+
j
,
那
么
A
x
=
(
A
m
)
i
∗
A
j
,
0
≤
i
<
m
,
0
≤
j
<
m
然
后
可
以
枚
举
i
,
这
是
O
(
C
)
级
别
的
枚
举
对
于
一
个
枚
举
出
来
的
i
,
令
D
=
(
A
m
)
i
。
现
在
问
题
转
化
为
求
D
∗
A
j
≡
B
m
o
d
C
,
如
果
把
A
j
当
作
一
个
整
体
,
套
上
拓
展
欧
几
里
得
算
法
就
可
以
解
出
来
了
。
(
而
且
因
为
C
是
质
数
,
A
是
C
的
倍
数
的
情
况
容
易
特
判
,
除
此
之
外
必
有
G
C
D
(
D
,
C
)
=
1
,
所
以
一
定
有
解
。
设m=\sqrt C上取整,x=i*m+j,那么A^x=(A^m)^i*A^j,0\le i<m,0\le j<m\\ 然后可以枚举i,这是O(\sqrt C)级别的枚举\\ 对于一个枚举出来的i,令D=(A^m)^i。现在问题转化为求D*A^j\equiv B\mod C,\\如果把A^j当作一个整体,套上拓展欧几里得算法就可以解出来了。\\(而且因为C是质数,A是C的倍数的情况容易特判,\\除此之外必有GCD(D,C)=1,所以一定有解。
设m=C上取整,x=i∗m+j,那么Ax=(Am)i∗Aj,0≤i<m,0≤j<m然后可以枚举i,这是O(C)级别的枚举对于一个枚举出来的i,令D=(Am)i。现在问题转化为求D∗Aj≡BmodC,如果把Aj当作一个整体,套上拓展欧几里得算法就可以解出来了。(而且因为C是质数,A是C的倍数的情况容易特判,除此之外必有GCD(D,C)=1,所以一定有解。
求出来
A
j
A^j
Aj,现在的问题是我怎么知道j是多少?先用
O
(
C
)
O(\sqrt C)
O(C)的时间,将A^j全部存进hash表里面,然后只要查表就在O(1)的时间内知道j是多少了。
luoguP2485 [SDOI2011]计算器
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll fpow(ll a,ll b,ll mod){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1,y=0;
return a;
}
ll gcd=exgcd(b,a%b,y,x);
y-=a/b*x;
return gcd;
}
void bsgs(ll y,ll z,ll p){
z%=p;
if(y%p==0){
if(z){
cout<<"Orz, I cannot find x!"<<endl;
return;
}else{
if(p==1){
cout<<0<<endl;
return;
}else{
cout<<1<<endl;
return;
}
}
}
ll m=ceil(sqrt(p));
map<ll,ll>mp;
ll now=z%p,f=fpow(y,m,p);
mp[now]=0;
for(int j=1;j<=m;j++){
now=now*y%p;
mp[now]=j;
}
now=1;
for(int i=1;i<=m;i++){
now=now*f%p;
if(mp[now]){
cout<<((i*m-mp[now])%p+p)%p<<endl;
return;
}
}
cout<<"Orz, I cannot find x!"<<endl;
}
int t,k,y,z,p;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>t>>k;
if(k==1){
for(int i=1;i<=t;i++){
cin>>y>>z>>p;
cout<<fpow(y,z,p)%p<<endl;
}
}else if(k==2){
for(int i=1;i<=t;i++){
cin>>y>>z>>p;
ll x,d;
ll gcd=exgcd(y,p,x,d);
if(z%gcd) cout<<"Orz, I cannot find x!"<<endl;
else{
ll tmp=p/gcd;
while(x<0) x+=tmp;
cout<<((x*z/gcd)%tmp+tmp)%tmp<<endl;
}
}
}else if(k==3){
for(int i=1;i<=t;i++){
cin>>y>>z>>p;
bsgs(y,z,p);
}
}
return 0;
}
拓展BSGS
不要求C为素数,开始前先执行消除因子。
$a\equiv b\mod p 可 转 化 为 可转化为 可转化为\frac{a}{c}\equiv\frac{b}{c}\mod \frac{p}{c}$
那么$a^x\equiv b\mod p 可 转 化 为 可转化为 可转化为a{x-k}\frac{ak}{\prod _{i-1}^kd_i}\equiv\frac{b}{\prod _{i-1}^kd_i}\mod \frac{p}{\prod _{i-1}^kd_i}$
步骤
(1)若b==1 那么x=0,算法结束;
(2)若gcd(a,p)不能整除b,则无解,算法结束;
(3)若gcd(a,p)!=1,令d=gcd(a,p),若d不能整除b,则无解,算法结束;
(4)持续步骤三直到 g c d ( A , p ∏ i − 1 k d i ) = 1 gcd(A,\frac{p}{\prod _{i-1}^kd_i})=1 gcd(A,∏i−1kdip)=1,我们就可以直接用普通BSGS求出结果,最后加上k即可。
luoguP4195 【模板】扩展 BSGS/exBSGS
#include<bits/stdc++.h>
#define LL long long
using namespace std;
int read(){ int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
unordered_map<int,int>mp;
inline int gcd(int a,int b){return b?gcd(b,a%b):a;}
inline int BSGS(int a,int n,int p,int ad){
mp.clear();
int m=ceil(sqrt(p)),s=1;
for(int i=0;i<m;i++,s=1ll*s*a%p) mp[1ll*s*n%p]=i;
for(int i=0,tmp=s,s=ad;i<=m;i++,s=1ll*s*tmp%p)
if(mp[s]) if(1ll*i*m-mp[s]>=0) return 1ll*i*m-mp[s];
return -1;
}
inline int exBSGS(int a,int n,int p){
a%=p;n%=p;
if(n==1||p==1) return 0;
int cnt=0;
int d,ad=1;
while((d=gcd(a,p))^1){
if(n%d) return -1;
cnt++;n/=d;p/=d;
ad=(1ll*ad*a/d)%p;
if(ad==n) return cnt;
}
LL res=BSGS(a,n,p,ad);
if(res==-1) return -1;
return res+cnt;
}
signed main(){
int a=read(),p=read(),n=read(),ans;
while(a||p||n){
ans=exBSGS(a,n,p);
if(~ans) printf("%d\n",ans);
else puts("No Solution");
a=read();p=read();n=read();
}
return 0;
}
参考资料
https://www.cnblogs.com/cytus/p/9296661.html
https://www.bilibili.com/video/BV14A411h7oD
https://www.bilibili.com/video/BV17f4y1v7D5