BSGS算法学习笔记

(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)算法。

蒟蒻我还没学,就先留坑待填吧。。。.

原文地址:https://www.cnblogs.com/dsjkafdsaf/p/11358518.html