zoukankan      html  css  js  c++  java
  • 大步小步法(BSGS) 学习笔记

    (\)

    BSGS


    用于求解关于 (x) 的方程:

    [a^xequiv bpmod p , (p,a)=1 ]

    一般求解的是模意义下的指数,也就是最小非负整数解。

    (\)

    算法思想


    本质是双向搜索,或阈值优化的思想。

    首先设"步幅" 为 (m=lceil{ sqrt p} ceil) ,然后将方程写作

    [a^{i imes m-j}equiv bpmod p ]

    其中 (i) 就是所谓"大步", (j) 就是所谓"小步",我们要把他们组合在一起。

    直接搜索两个数不如折半搜索一个数,然后再组合。

    于是我们可以将分母上的 (a^j) 移项,得到

    [a^{i imes m}equiv b imes a^jpmod p ]

    然后就成了比较标准的双向搜索形式。

    先把右一半的答案记下来,然后拿左一半搜到的每一个数去查询是否出现过就好了。

    (\)

    代码实现


    对于每一个 (jin [0,m-1]) ,将 (b imes a^j \% p) 的答案放到哈希表里。

    然后对于每一个 (iin[1,m]() 此范围依据定义而来,尤其注意!()),去哈希表里查是否有 (a^{im} \% p) 的值。

    还有两个小优化:

    • 注意到求出为同一个值的 (j) ,因为在答案里系数为 (-1) ,所以对于求出最小解 (j) 肯定是越大越优秀。

      因此再哈希表里插入相同的值时,可以直接取 (max), 如果是按序插入直接覆盖即可。

      这里也延申出了一种做法,直接用 (map) 存储结果,将结果映射到 (j) ,按序插入直接覆盖,复杂度多个(log)

    • 运算过程中只需一次快速幂。

      一开始每一次都是乘上 (a) ,所以一遍循环一遍乘即可,第二步同理,只需题前计算出 (a^m) 的值。

      这一优化在需要快速乘的时候效果很好。

    我们以 [TJOI2007]可爱的质数 一题为例提供一份模板。

    #include<map>
    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define R register
    using namespace std;
    typedef long long ll;
    
    map<ll,ll> s;
    
    inline ll qpow(ll x,ll t,ll p){
      ll res=1;
      while(t){
        if(t&1) (res*=x)%=p;
        (x*=x)%=p; t>>=1;
      }
      return res;
    }
    
    inline ll BSGS(ll a,ll b,ll p){
      b%=p;
      ll m=ceil(sqrt(p));
      for(R ll i=0;i<m;++i,(b*=a)%=p) s[b]=i;
      a=qpow(a,m,p);
      for(R ll i=1,tmp=a;i<=m;++i,(tmp*=a)%=p)
        if(s.find(tmp)!=s.end()){
          if(i*m<s[tmp]) continue;
          return i*m-s[tmp];
        }
      return -1;
    }
    
    int main(){
      ll a,b,p;
      scanf("%lld%lld%lld",&p,&a,&b);
      ll x=BSGS(a,b,p);
      if(x>=0) printf("%lld
    ",x);
      else puts("no solution");
      return 0;
    }
    
    
  • 相关阅读:
    【转】Chrome 控制台不完全指南
    AngularJS 之 Factory vs Service vs Provider【转】
    【转】NuGet.org 无法访问的解决方法
    jquery easyui 1.4.1 验证时tooltip 的位置调整
    jquery easyui 1.4.1 API( CHM版)
    扩展 easyui-tabs 插件 关闭标签页方法
    easyui layout 折叠后显示标题
    easyui 中Datagrid 控件在列较多且无数据时,列显示不全的解决方案
    为easyui datagrid 添加上下方向键移动
    Android布局实现圆角边框
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9988366.html
Copyright © 2011-2022 走看看