BSGS
作用
大步小步法(Baby-Step-Giant-Step,简称BSGS,至于为什么叫大步小步法,不是很清楚啊QAQ),可以较高效的求解形如 Ax≡B(mod C) (C是素数)的同余方程。
方法
ps:接下来讨论的都是(A,C)=1(由于C是素数,所以等价于A不是C倍数)的情况,如果(A,C)>1(A是C倍数),很容易特判掉。
在说BSGS之前,先来证明一个结论:
如果(A,C)=1,那么对于x∈N,有
Ax
mod
φ(C)≡Ax(mod
C)
。
证明:因为(A,C)=1,根据欧拉定理,得
Aφ(C)≡1(mod
C)
设k∈N,根据同幂性,得
Ak∗φ(C)≡1(mod
C)
设a∈N且a<φ(C),所以
Ak∗φ(C)+a≡Aa(mod
C)
即
Ax
mod
φ(C)≡Ax(mod
C)
,得证。
所以如果0<=x<φ(C)无解,之后肯定也无解(循环了)。不过值得一提的是,φ(C)并不是一定最小正周期,随便造点数据都可以验证。
接下来我们正式开始讲BSGS。这个算法实际上是利用了分块思想来优化暴力枚举,令m= ⌈C−−√⌉ ,我们假设 x=i∗m+j(0<=i<m,0<=j<m,i,j∈N) ,那么也就是说 Ax=Ai∗m∗Aj 。
令D= Ai∗m ,则原方程可转化为 D∗Aj≡B(mod C) 。用扩展欧几里得就可以求出 Aj 了。然而知道 Aj 好像并没有什么用,因为我们要求的是j。所以这里我们要用到巧妙的预处理(分块+预处理大法好!),就是先把 Aj 全部存进哈希表里(map也可以,就是常数大),然后就可以近似 O(1) 求出j了!
扩展BSGS
作用
BSGS只能处理C是素数的情况,太特殊了,应用范围不大。而扩展BSGS可以解决C不是素数的一般情况。
方法
设d=gcd(A,C),那么A,B,C可以表示为A=a*d,B=b*d(如果B不是d的倍数且B!=1则显然无解),C=c*d。也就是说
(a∗d)x≡b∗d(mod
c∗d)
。
根据同余性质,这个式子可以同除d,得到
a∗(a∗d)x−1≡b(mod
c)
,如果我们把D*=a(D就是之前的D=
Ai∗m
),那么前面就剩下
(a∗d)x−1
了,不停求d=gcd(A,C),然后将B/=d,C/=d(A不变,因为是
Ax
),D*=A/d,num++,直到d=1为止。
最后方程就变成这种形式了: D∗Ax−num≡B(mod C) 。令x=i*m+j+num,那么和原先的BSGS一样处理就行了。只不过我们会发现由于 0<=i<m,0<=j<m ,所以x将会>=num,这就导致0~num-1枚举不到。所以要在最开始枚举一下0~num-1,这个问题就解决了。