zoukankan      html  css  js  c++  java
  • BSGS算法初探

    前言

    \(BSGS\)算法,全称\(Baby\ Step\ Giant\ Step\),即大小步算法。某些奆佬也称其为(Ba)(Shan)(Gai)(Shi)算法。

    它的主要作用是求解形式如\(x^t\equiv y(mod\ MOD)\)的式子中\(t\)的值\((gcd(x,MOD)=1)\)

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

    一个简单的性质

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

    费马小定理可得,\(x^{MOD-1}\equiv1(mod\ MOD)\)

    因此,当\(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^{i*Size}\equiv x^j*y(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(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
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    类和对象
    类和对象1
    常见的子串问题
    常见的算法问题全排列
    第六届蓝桥杯java b组第五题
    第六届蓝桥杯java b组第四题
    第六届蓝桥杯java b组第三题
    第六届蓝桥杯java b组第二题
    第六届蓝桥杯java b组第一题
    第八届蓝桥杯java b组第三题
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BSGS.html
Copyright © 2011-2022 走看看