BSGS算法初探
前言
$BSGS$算法,全稱$Baby Step Giant Step$,即大小步算法。某些奆佬也稱其為拔(Ba)山(Shan)蓋(Gai)世(Shi)算法。
它的主要作用是求解形式如$x^t\equiv y(mod MOD)$的式子中$t$的值。
而且,它是一個簡單易懂的算法(畢竟連我這樣的數學渣渣都能理解)。
一個簡單的性質
首先,我們需要知道一個簡單的性質。
由費馬小定理可得,$x^{MOD-1}\equiv1(mod MOD)$。
$Link$
費馬小定理詳見博客篩素數方法(二)—— 費馬小定理及MR素數判斷
因此,當$t\ge MOD-1$時,會出現一個循環節。
於是我們就能保證答案$t$如果存在,則必然$<MOD-1$
這是一個簡單而又重要的性質。
$BSGS$算法的主要思想
$BSGS$算法的主要思想就是兩個字:分塊(提到分塊就要$%$一波分塊奆佬$hl666$)。
根據分塊思想,我們設一個變量$Size=\sqrt{MOD}$(註意,此處要用$ceil$函數向上取整,這樣才能保證$Size*Size\ge MOD$,不然可能會遺漏答案)。
不難發現,此時的$t$可以表示為$i*Size-j$($i,j$均為非負整數且$j<Size$)。
那麽原式就被轉化成了$x^{i*Size-j}\equiv y(mod MOD)$。
移項得$x^{iSize}\equiv x^jy(mod MOD)$。
然後怎麽處理呢?
我們可以對$x^j*y$的值進行一波預處理,用一個$map$存儲下來。
然後枚舉$i$,判斷$x^{i*Size}$的值是否存在即可。
當找到一個合法的$i$後,最終的答案就是$i*Size-j$。
時間復雜度分析
預處理的時間復雜度顯然是$O(j)$的,枚舉$i$的時間復雜度顯然是$O(i)$的。
又由於$i$和$j$都是$O(\sqrt 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(i=1;i<=Size;++i,x=1LL*x*base%MOD)//枚舉i,每次將t乘上x^Size if(s[t]) return i*Size-s[t];//找到一個合法的i,則答案就是i*Size-j return 0;//無解返回0 }
BSGS算法初探