(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
",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
",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
",(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
",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)算法。
蒟蒻我还没学,就先留坑待填吧。。。.