BSGS 大步小步算法
BSGS 大步小步算法
,大步小步算法(轻量级算法,求解高次同余方程)。
思路
先上例题:给定整数 ,其中 互质,求一个非负整数 ,使得
朴素算法概述:
考虑一个暴力算法,在 的意义下, 显然有一个长度为 的循环节,所以只需要考虑 的情况即可。
暴力枚举 x
求解,时间复杂度 ,最坏
而 则运用类似于 拆半搜索 的思想,将 x
表示成 的形式。
于是原式
固定 t
的值,预处理出右式所有可能的取值。
枚举计算左式可能的值,当枚举到某个在右边已经出现过的值时,此时 就是我们要求的 x
。
t
的取值:
的取值为 共计 个, 的取值有 个。
取 时有最优复杂度(最平均),但为避免计算 ,近似取 即可。
时间复杂度
exBSGS
求解 需要满足条件 ,而 (扩展 )主要解决 的情况。
设 ,若我们把同余式两边同时除以 ,如此可以构造互质。
因为 ,所以 时,必然有 ,否则原同余式无解。
于是原式
运用 ,原式
但是 不一定与 互质,于是递归进入子问题求解,直到 与模数互质()为止。
完美解决,撒花。
练习题目
可爱的质数/[模板]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/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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具