【模板】BSGS

【模板】BSGS

我们一般叫他北上广深算法。

Part 1. BSGS 是干什么的

求解如下问题:

已知 a , b , p a,b,p a,b,p,求最小的正整数 x x x 使得 a x ≡ b ( m o d p ) a^x\equiv b\pmod p axb(modp),保证 p p p 是质数。

Part 2. 做法

由欧拉定理我们可以知道:
a φ ( p ) ≡ 1 ( m o d p ) a^{\varphi(p)}\equiv 1\pmod p aφ(p)1(modp)

又因为:
a 0 ≡ 1 ( m o d p ) a^0\equiv 1\pmod p a01(modp)

所以可以发现 [ 0 , φ ( p ) − 1 ] [0,\varphi(p)-1] [0,φ(p)1] a i a_i ai 的循环节,考虑枚举一定范围来求解。

我们设 x = i k − j ( 0 ⩽ j < k ) x=ik-j(0\leqslant j<k) x=ikj(0j<k),可以得到 a i k − j ≡ b ( m o d p ) a^{ik-j}\equiv b\pmod p aikjb(modp),转化为:
a i k ≡ b a j ( m o d p ) a^{ik}\equiv ba^j\pmod p aikbaj(modp)

于是我们考虑将所有的 b a j   m o d   p ba^j\bmod p bajmodp 求出来,显然有 k k k 个,塞入哈希表里,枚举 i ∈ [ 0 , k ] i\in[0,k] i[0,k],查找对应的 b a j ba^j baj 值,即可得到答案。
现在我们的复杂度是 O ( max ⁡ ( k , φ ( p ) k ) ) \mathcal{O}\left(\max\left(k,\dfrac{\varphi(p)}{k}\right)\right) O(max(k,kφ(p))),由基本不等式取 k = ⌈ p ⌉ k=\lceil\sqrt{p}\rceil k=p 时时间复杂度最优。

特别要注意的是,一定不能取在 ⌊ p ⌋ \lfloor\sqrt{p}\rfloor p ,要么向上取整,要么使用向下取整 + 1 +1 +1
如果我们使用 map 进行哈希表处理可以得到时间复杂度 O ( p log ⁡ p ) \mathcal{O}(\sqrt{p}\log p) O(p logp),用普通的哈希表或者 unordered_map 可以做到 O ( p ) \mathcal{O}(\sqrt p) O(p )

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
    char op=getchar();
    int w=0,s=1;
    while(op<'0'||op>'9'){
        if(op=='-') s=-1;
        op=getchar();
    }
    while(op>='0'&&op<='9'){
        w=(w<<1)+(w<<3)+op-'0';
        op=getchar();
    }
    return w*s;
}
int mod;
int Mul(int a,int b){return (a%mod*b%mod)%mod;}
int Add(int a,int b){return (a+b)%mod;}
int Dec(int a,int b){return (a-b+mod)%mod;}
int Pow(int a,int k){
    int ans=1;
    while(k){
        if(k&1) ans=Mul(ans,a);
        a=Mul(a,a);
        k>>=1;
    }
    return ans;
}
map<int,int> mp;
signed main(){
    int p=read(),a=read(),b=read();
    mod=p;
    int k=sqrt(p)+1;
    for(register int i=0,cnt=b;i<=k;i++,cnt=Mul(cnt,a)) mp[cnt]=i;
    int now=Pow(a,k);
    for(register int i=1,cnt=now;i<=k;i++,cnt=Mul(cnt,now)){
        if(mp.count(cnt)!=0){
            printf("%lld",i*k-mp[cnt]);
            return 0;
        }
    }
    printf("no solution");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值