BSGS & exBSGS 总结

BSGS

求解 \(a\) 在模 \(m\) 意义下的 \(b\) 离散对数,满足 \(\gcd(a,m)=1\)

即求最小的非负数 \(x\) 满足 \(a^x \equiv b \pmod m\)

考虑取 \(t=\lceil \sqrt p \rceil\),令 \(x = i \times t - j\),满足 \(1 \le i \le t,0\le j < t\)

因为:

\[a^{i \times t - j} \equiv b \pmod m \]

两边同乘 \(a^{j}\)

\[a^{i \times t} \equiv ba^{j} \pmod m \]

枚举 \(j\),将右边的数插入到哈希表中,最后枚举 \(i\),在哈希表中查询即可,时间复杂度 \(\Theta(\sqrt p)\)

int bsgs(int a,int b,int p)
{
    if(p==1) return 0;
    a%=p,b%=p;
    if(b&&a==0) return p==1?0:-1;
    if(a==b) return 1;
    unordered_map<int,int> hs;
    int t=ceil(sqrt(1.0*p));
    for(int j=0,v=b;j<=t;++j)
    {
        hs[v]=j;
        v=v*a%p;
    }
    for(int i=1,v=qpow(a,t,p),temp=qpow(a,t,p);i<=t;++i)
    {
        if(hs.count(v))
        {
            return i*t-hs[v];
        }
        v=v*temp%p;
    }
    return -1;
}

代码细节整理:

  1. 如果不保证 \(a < p,b<p\),开始时要先模一下。

    正确性:对 \(b\) 是显然的,对 \(a\) 来说由于 \((a+kp)^x\) 的 展开中,只有 \(a^x\) 是有贡献的,含有 \((kp)^x\) 的项在模 \(p\) 意义下都是 \(0\)

  2. \(p=1\) 时,\(x=0\)

  3. \(a=b\) 时,\(x=1\)

  4. 如果 \(a \bmod p = 0\),那么 \(b \not = 0\)\(p \not = 1\) 时无解。

exBSGS

求解 \(a\) 在模 \(m\) 意义下的 \(b\) 离散对数,不一定满足 \(\gcd(a,m)=1\)

即求最小的非负数 \(x\) 满足 \(a^x \equiv b \pmod m\)

由于 \(a,m\) 不一定互质,考虑化成互质的情况用 BSGS 求解。

同余的一条性质:若 \(a \equiv b \pmod m\),即 \(d = \gcd(a,m)\),那么 $\frac{a}{d} \equiv \frac{b}{d} \pmod {\frac{m}{d}} $

故先取 \(d_1 = \gcd(a,m)\),得到:

\[\frac{a}{d_1}a^{x-1} \equiv \frac{b}{d_1} \pmod {\frac{m}{d_1}} \]

如果 \(a,\frac{m}{d_1}\) 仍然不互质,就取 \(d_2 = \gcd(a,\frac{m}{d_1})\) 继续操作,直到 \(a\) 与模数互质:

\[\frac{a}{\prod_{i=1}^{k}d_i} a^{x-k} \equiv \frac{b}{\prod_{i=1}^{k}d_i} \pmod {\frac{m}{\prod_{i=1}^{k}d_i}} \]

\(A=\frac{a}{\prod_{i=1}^{k}d_i} a^{x-k},M=\frac{m}{\prod_{i=1}^{k}d_i},B=\frac{b}{\prod_{i=1}^{k}d_i}\),二者互质,存在逆元,方程转化为:

\[a^{x-k} \equiv B \times A^{-1} \pmod M \]

用普通 BSGS 求解即可。

int exbsgs(int a,int b,int p)
{
    a%=p,b%=p;
    if(b==1||p==1) return 0;
    int k=0;
    int D=1,d,ad=1;
    while((d=gcd(a,p))!=1)
    {
        if(b%d) return -1;
        D*=d,b/=d,p/=d;
        ad=(ad*a/d)%p;
        ++k;
        if(ad==b) return k;
    }
    int ans=bsgs(a,b*inv(ad,p)%p,p);
    return ans==-1?ans:ans+k;
}

代码细节整理:

  1. 像普通 BSGS 一样,注意特判 \(p=1,b=1\) 的情况。
  2. 不断除以 \(d\) 的时候,出现 \(A=B\) 的时候 \(x\) 的最小值就是 \(k\)
posted @ 2025-04-18 14:59  vanueber  阅读(18)  评论(0)    收藏  举报