大小步算法 BSGS

前提:

当你遇到一个形如

axb(modp),  pgcd(a,p)=1x

的问题时,你可能会苦恼。

但是对于条件 p 为素数且 gcd(a,p)=1,你可能会想到 费马小定理ap11(modp)

所以可以把 x 分解为 k×(p1)+t,这样就可以得出 kap1,然后可以在 [0,p1] 中枚举 t 来求解。

但此时的时间复杂度为 O(p),通常一个 p 是一个极大的数,所以并不是很优秀的做法。


大小步算法。

大小步算法(Boby-Step-Giant-Step)也被称为拔山盖世算法、北上广深算法...

如果有人对 分块 或者 筛法 有了解的话,将一个数开方是优秀的复杂度,

那么大小步算法结合这个特点,将 x 分为了 i×pj 的形式。

  1. m=p,原来的方程就变为了

ai×mjb(modp)

  1. 由此我们在方程的两边分别乘上 aj,得到

(am)ib×aj(modp)

  1. 既然要找出两个相等的数,何必不用 hash 表来快速查询呢

    • 先从 0m 枚举 j,将 b×aj 存入 hash 表中。(Boby-Step)
    • 再从 1m 枚举 i,将 (am)ihash 表中查询。(Giant-Step)
  2. 因为从小到大枚举,所以找到的第一个 j,就是满足 x 为最小整数解。


代码实现

unordered_map<int,int>vis;

void BSGS()
{
	cin >> p >> a >> b;
	a %= p; b %= p;
	m = ceil(sqrt(p));
	am = Pow(a,m,p);
	cur = 1;
	for (int j = 0; j <= m; ++ j)
	{
		vis[b*cur%p] = j;
		cur = (cur * a) %p;
	}
	cur = 1;
	for (int i = 1; i <= m; ++ i)
	{
		cur = (cur * am) %p;
		if (vis.find(cur) != vis.end())
		{
			cout << i*m-vis[cur];
			return;
		}
	}
	cout << "no solution";
}

再来一遍!

我们的答案皆出自于 a0,a1,a2,,ap2p1 个数中。

那么将其分为若干组,每个组的大小均设为 s。那么相邻的每个组的对应的数之间就会相差 ×as

  • 假如,答案 x 在第 2 组中出现了,那么在第 1 组中就会有 b×as 出现。

那么就可以只处理出一组的答案,然后再对所有的 b×aks 查询(二分、哈希等)即可。

posted @   Ciaxin  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示