BSGS 大步小步算法

BSGS 大步小步算法

Baby Step,Giant Step,大步小步算法(轻量级算法,求解高次同余方程)。

思路

先上例题:给定整数 a,b,p,其中 a,p 互质,求一个非负整数 x,使得 axb(modp)

朴素算法概述:

考虑一个暴力算法,在 mod p 的意义下,ax 显然有一个长度为 φ(p) 的循环节,所以只需要考虑 xφ(p) 的情况即可。

暴力枚举 x 求解,时间复杂度 O(φ(p)),最坏 O(p1)

BSGS 则运用类似于 拆半搜索 的思想,将 x 表示成 i×tj 的形式。

于是原式 ai×tb×aj(modp)

固定 t 的值,预处理出右式所有可能的取值。

枚举计算左式可能的值,当枚举到某个在右边已经出现过的值时,此时 i×tj 就是我们要求的 x

t 的取值:

j 的取值为 φ(p)modt 共计 t1 个,i 的取值有 φ(p)t 个。

tφ(p) 时有最优复杂度(最平均),但为避免计算 φ(p),近似取 t=p 即可。

时间复杂度 O(p)

exBSGS

求解 axb(modp) 需要满足条件 ap ,而 exBSGS (扩展 BSGS)主要解决 a⊥̸p 的情况。

d=gcd(a,p),若我们把同余式两边同时除以 d ,如此可以构造互质。

因为 daxmodp,所以 b1 时,必然有 db ,否则原同余式无解。

于是原式 ax1adbd(modpd)

运用 exgcd ,原式 ax1bd(ad)1(modpd)

但是 a 不一定与 pd 互质,于是递归进入子问题求解,直到 a 与模数互质(d=1)为止。

完美解决,撒花。

练习题目

可爱的质数/[模板]BSGS

模板。

class BSGS{
public:
    LL mod, a, b, t, power;
    std::unordered_map<LL, int> hash;
    BSGS(LL _a, LL _b, LL _mod){a = _a, b = _b, mod = _mod, t = std::ceil(std::sqrt(mod)) + 1, power = 1;};
    int work()
    {
        for (int j = 0; j < t; j++)
            hash[b * power % mod] = j, power = power * a % mod;
        LL res = power;
        for (int i = 1; i <= t; i++)
        {
            auto iter = hash.find(power);
            int val = iter != hash.end() ? iter->second : mod;
            if (val != mod)
                return i * t - val;
            power = power * res % mod;
        }
        return -1;
    }
};
int main()
{
    BSGS bsgs(/*a, b, p*/);
    std::cout << bsgs.work();
    return 0;
}

多少个1?

再送一道 bsgs 模板。

[ 模板]扩展 BSGS/exBSGS

exbsgs 的模板题。

#include <bits/stdc++.h>
using LL = long long;
class BSGS{
public:
    LL mod, a, b, t, power;
    std::unordered_map<LL, int> hash;
    BSGS(LL _a, LL _b, int _mod){a = _a, b = _b, mod = _mod, t = std::ceil(std::sqrt(mod)), power = 1;};
    int work()
    {
        hash.clear();
        for (int j = 0; j < t; j++)
            hash[b * power % mod] = j, power = power * a % mod;
        LL res = power;
        for (int i = 1; i <= t; i++)
        {
            auto iter = hash.find(power);
            int val = iter != hash.end() ? iter->second : mod;
            if (val != mod)
                return i * t - val;
            power = power * res % mod;
        }
        return -10000;
    }
}bsgs(0, 0, 0);
void exgcd(LL a, LL b, LL &x, LL &y)
{
    if (b == 0)
        return void(x = 1), void(y = 0);
    exgcd(b, a % b, x, y);
    LL z = x;
    x = y, y = z - y * (a / b);
}
LL inv(LL a, int mod)
{
    LL x, y; exgcd(a, mod, x, y);
    return (x % mod + mod) % mod;
}

LL dfs(LL a, LL b, LL mod)
{
    if (a == b) return 1;
    LL d = std::__gcd(a, mod);
    if (d == 1) return void(bsgs = BSGS(a, b, mod)), bsgs.work();
    if (b % d) return -10000;
    mod /= d;
    return dfs(a % mod, (b / d) * inv(a / d, mod) % mod, mod) + 1;
}

int main()
{
    LL a, b;
    int mod;
    auto work = [](LL a, LL b, int mod)->LL{
        if (b == 1 || mod == 1) return 0;
        if (!a) return b ? -1 : 1;
        if (b == 1) return 0;
        return dfs(a, b, mod);
    };
    while (1)
    {
        scanf("%lld %d %lld", &a, &mod, &b);
        if (!mod) break;
        a %= mod, b %= mod;
        LL ans = work(a, b, mod);
        if (ans >= 0) printf("%lld\n", ans);
        else puts("No Solution");
    }
    return 0;
}
posted @   mklzc  阅读(85)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示