BSGS算法初探

前言

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

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

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


一个简单的性质

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

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

L i n k Link Link

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

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

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

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


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

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

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

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

那么原式就被转化成了 x i ∗ S i z e − j ≡ y ( m o d   M O D ) x^{i*Size-j}\equiv y(mod\ MOD) xiSizejy(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) xiSizexjy(mod MOD)

然后怎么处理呢?

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

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

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


时间复杂度分析

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

又由于 i i i j j j都是 O ( N ) O(\sqrt N) O(N )大小的,所以总复杂度也是 O ( N ) O(\sqrt N) O(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
}

你可能感兴趣的:(BSGS)