\(BabyStepGiantStep\)算法,即大步小步算法,缩写为\(BSGS\)
这是一种解高次离散对数的东西。。。
就是形如\(y^x \equiv z \%p\),\(x\)的最小整数解。
\(BSGS\)算法的算法前提是\(p\)为质数。
首先,我们令\(x=a*m-b\),则原式为\(y^{a*m-b} \equiv z\%p\)。
即\(y^{a*m} \equiv z*y^b\%p\),同时,\(y\)和\(z\)以及\(m\)是常量。
我们发现,当我们枚举\(b\)时,模方程的右边是一个定值,我们可以将其利用哈希表存下来。
然后,我们枚举左边的\(a\),当我们枚举一个值时发现哈希表中出现了该值,那我们就可以更新答案了。
现在的问题是,我们该如何定义\(m\)使总复杂度最小?
时间复杂度为枚举右边的复杂度,由于右边的\(b\)是\(\in [0,m)\),所以枚举复杂度为\(O(m)\)。
左边的枚举是到\(p/m\)的,即时间复杂度为\(O(p/m)\)。
所以总时间复杂度为\(O(p/m+m)\),由均值不等式可得,最低时间复杂度为,当\(m\)取\(\sqrt p\)时的\(O(2*\sqrt p)\)。
代码如下:
map<int,int>vis;
inline void solve(void) {
x=Read(),y=Read(),p=Read();
x%=p,y%=p;
if(y==1)return(void)puts("0");
vis.clear();
int res=y,m=sqrt(p)+1;
ret(i,0,m)vis[res]=i,res=(res*x)%p;
int step=Pow(x,m);
res=1;
rep(i,1,m) {
res=(res*step)%p;
if(vis.count(res))return(void)printf("%lld\n",i*m-vis[res]);
}
}
这里有一道模板题:https://www.lydsy.com/JudgeOnline/problem.php?id=2242
代码如下:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define reg register
#define Raed Read
#define debug(x) cerr<<#x<<" = "<<x<<endl;
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,G,x) for(int i=(G).Head[x]; i; i=(G).Nxt[i])
inline int Read() {
int res = 0, f = 1;
char c;
while (c = getchar(), c < 48 || c > 57)if (c == '-')f = 0;
do res = (res << 3) + (res << 1) + (c ^ 48);
while (c = getchar(), c >= 48 && c <= 57);
return f ? res : -res;
}
template<class T>inline bool Min(T &a, T const&b) {
return a > b ? a = b, 1 : 0;
}
template<class T>inline bool Max(T &a, T const&b) {
return a < b ? a = b, 1 : 0;
}
const int N=5e4+5,M=5e4+5,mod=1e9+7;
bool MOP1;
int x,y,p;
inline int Pow(int x,int y) {
int res=1;
while(y) {
if(y&1)res=(res*x)%p;
x=(x*x)%p,y>>=1;
}
return res;
}
inline void No(void) {
puts("Orz, I cannot find x!");
}
struct T1 {
inline void solve(void) {
x=Read(),y=Read(),p=Read();
printf("%lld\n",Pow(x,y));
}
} P1;
struct T2 {
inline void solve(void) {
x=Read(),y=Read(),p=Read();
if(x%p==0)return(void)No();
printf("%lld\n",(y*Pow(x,p-2))%p);
}
} P2;
struct T3 {
map<int,int>vis;
inline void solve(void) {
x=Read(),y=Read(),p=Read();
if(x%p==0)return(void)No();
x%=p,y%=p;
if(y==1)return(void)puts("0");
vis.clear();
int res=y,m=sqrt(p)+1;
ret(i,0,m)vis[res]=i,res=(res*x)%p;
int step=Pow(x,m);
res=1;
rep(i,1,m) {
res=(res*step)%p;
if(vis.count(res))return(void)printf("%lld\n",i*m-vis[res]);
}
No();
}
} P3;
bool MOP2;
inline void _main(void) {
int T=Read(),k=Read();
while(T--) {
if(k==1)P1.solve();
if(k==2)P2.solve();
if(k==3)P3.solve();
}
}
signed main() {
_main();
return 0;
}
上文已经提到了,普通的\(BSGS\)算法只能解决\(p\)为质数的情况,至于\(p\)不为质数的情况,就要用到扩展\(BSGS\)算法。
蒟蒻我还没学,就先留坑待填吧。。。.