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

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

转载于:https://www.cnblogs.com/dsjkafdsaf/p/11358518.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值