BSGS算法初探

版权声明:此文为作者原创,若觉得写得好请点个赞再离开。当然,也欢迎在讨论区指出本文的不足,作者会及时加以改正。转载请注明地址: https://blog.csdn.net/chenxiaoran666/article/details/83450304

前言

B S G S BSGS 算法,全称 B a b y   S t e p   G i a n t   S t e p Baby\ Step\ Giant\ Step ,即大小步算法。某些奆佬也称其为(Ba)(Shan)(Gai)(Shi)算法。

它的主要作用是求解形式如 x t y ( m o d   M O D ) x^t\equiv y(mod\ MOD) 的式子中 t t 的值。

而且,它是一个简单易懂的算法(毕竟连我这样的数学渣渣都能理解)。


一个简单的性质

首先,我们需要知道一个简单的性质。

费马小定理可得, x M O D 1 1 ( m o d   M O D ) x^{MOD-1}\equiv1(mod\ MOD)

L i n k Link

费马小定理详见博客筛素数方法(二)—— 费马小定理及MR素数判断

因此,当 t M O D 1 t\ge MOD-1 时,会出现一个循环节。

于是我们就能保证答案 t t 如果存在,则必然 < M O D 1 <MOD-1

这是一个简单而又重要的性质。


B S G S BSGS 算法的主要思想

B S G S BSGS 算法的主要思想就是两个字:分块(提到分块就要 % \% 一波分块奆佬 h l 666 hl666 )。

根据分块思想,我们设一个变量 S i z e = M O D Size=\sqrt{MOD} (注意,此处要用 c e i l ceil 函数向上取整,这样才能保证 S i z e S i z e M O D Size*Size\ge MOD ,不然可能会遗漏答案)。

不难发现,此时的 t t 可以表示为 i S i z e j i*Size-j i , j i,j 均为非负整数且 j < S i z e j<Size )。

那么原式就被转化成了 x i S i z e j y ( m o d   M O D ) x^{i*Size-j}\equiv y(mod\ MOD)

移项得 x i S i z e x j y ( m o d   M O D ) x^{i*Size}\equiv x^j*y(mod\ MOD)

然后怎么处理呢?

我们可以对 x j y x^j*y 的值进行一波预处理,用一个 m a p map 存储下来。

然后枚举 i i ,判断 x i S i z e x^{i*Size} 的值是否存在即可。

当找到一个合法的 i i 后,最终的答案就是 i S i z e j i*Size-j


时间复杂度分析

预处理的时间复杂度显然是 O ( j ) O(j) 的,枚举 i i 的时间复杂度显然是 O ( i ) O(i) 的。

又由于 i i j j 都是 O ( N ) O(\sqrt N) 大小的,所以总复杂度也是 O ( N ) O(\sqrt N) 级别的,是一个比较优秀的算法。


代码

map<int,int> s;//定义一个map
inline int BSGS(int x,int y,int MOD)//对于一个式子x^t=y(mod MOD),求出t的值
{
	register int i,t=1,base,Size=ceil(sqrt(MOD));//注意此处要用ceil函数向上取整
	for(i=0;i<=Size;++i) s[1LL*t*y%MOD]=i,base=t,t=1LL*t*x%MOD;//预处理将(x^j)*y的值全部用map存下对应的j,并用base存储下x^Size
	for(t=base,i=1;i<=Size;++i,t=1LL*t*base%MOD)//枚举i,每次将t乘上x^Size 
		if(s[t]) return i*Size-s[t];//找到一个合法的i,则答案就是i*Size-j
	return 0;//无解返回0
}

猜你喜欢

转载自blog.csdn.net/chenxiaoran666/article/details/83450304