zoukankan      html  css  js  c++  java
  • 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)算法。

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

  • 相关阅读:
    Dagger2使用
    Android自定义processor实现bindView功能
    Android注解方式实现表单校验
    一次简单的SQL手工注入
    Drozer简单使用
    Android刷机
    Python Network Security Programming-1
    存在于文件名中的SQL手工注入
    java 动手动脑7
    Java课堂 动手动脑6
  • 原文地址:https://www.cnblogs.com/dsjkafdsaf/p/11358518.html
Copyright © 2011-2022 走看看