• [拓展Bsgs] Clever


    题目链接 Clever - Y

     

    题意

     有同余方程 (X^Y equiv K (mod Z)),给定(X)(Z)(K),求(Y)

    解法

     如题,是拓展 (Bsgs) 板子,部分学习内容在这里 ((Click here))
     
     敲完板子就能获得至少 5 倍经验。
     
     过程中疯狂 (WA) 所以总结需要注意的几点……
     
      · 令 (m = sqrt(p) + 1) 比较保险,不然有的时候会枚举不到
      · 在令 (a)(p) 互质的循环中,(b = d) 时及时返回是有必要的
      · 同时在以上步骤中,((a, p)) 可能恒不等于(1),所以也要判
      · (map) 慢的一批!慢的一批!手写个效率有保证的类似哈希表的东西

    类似的题目

     [Hdu 2815] Mod Tree
     [Poj 2417] Discrete Logging
     [CQOI2018] 破解D-H协议

     代码……
     

    #include <cmath>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    typedef long long u64;
    
    class Hash_table {
    private:
      vector<u64> value;
      vector<pair<u64, u64> > funcn;
    public:
      inline void clear() { value.clear(), funcn.clear(); }
    
      inline void sortv() { sort(value.begin(), value.end()); }
    
      inline void push(u64 x, u64 p) { value.push_back(x), funcn.push_back(make_pair(x, p)); }
    
      inline bool find(u64 x) {
        int k = lower_bound(value.begin(), value.end(), x) - value.begin();
        return (k != value.size()) && (value[k] == x);
      }
    
      inline int posi(u64 x) {
        for(int i = 0; i < funcn.size(); ++i)
          if( funcn[i].first == x ) return funcn[i].second;
      }
    } lg;
    
    inline u64 Fast_pow(u64 x, u64 p, u64 m) {
      u64 ans = 1;
      if( p < 0 ) return ans;
      for( ; p; x = x * x % m, p = p >> 1) if( p & 1 ) ans = x * ans % m;
      return ans;
    }
    
    inline u64 Ex_gcd(u64 a, u64 b, u64 &x, u64 &y) {
      if( !b ) { x = 1, y = 0; return a; }
      u64 d = Ex_gcd(b, a % b, y, x); y = y - a / b * x;
      return d;
    }
    
    inline u64 Gcd(u64 a, u64 b) { return !b ? a : Gcd(b, a % b); }
    
    inline u64 Inverse(u64 a, u64 p) {
      u64 x = 0, y = 0, g = Ex_gcd(a, p, x, y);
      return g == 1 ? (x + p) % p : -1ll;
    }
    
    inline u64 Solve_fun(u64 a, u64 b, u64 p) {
      u64 g = Gcd(a, p), inv = 1, x = 0, y = 0;
      if( b % g ) return -1ll;
      a = a / g, b = b / g, p = p / g;
      inv = Inverse(b, p), a = a * inv % p, b = 1;
      Ex_gcd(a, p, x, y), x = (x + p) % p;
      return ~inv ? x : -1ll;
    }
    
    inline u64 Ex_bsgs(u64 a, u64 b, u64 p) {
      u64 m = 1, d = 1, num = 0, base = 1, pow_a = 1, ans = -1;
      for(u64 g = Gcd(a, p); g != 1ll; g = Gcd(a, p), ++num) {
        if( num > 31 || b % g ) return -1ll;
        b = b / g, p = p / g, d = d * (a / g) % p;
        if( b == d ) return num + 1;
      }
      m = sqrt(p) + 1, base = Fast_pow(a, m, p), lg.clear(), lg.push(1ll, 0ll);
      for(u64 i = 1; i <= m + num; ++i) pow_a = pow_a * a % p, lg.push(pow_a, i);
      lg.sortv();
      for(u64 tmp, i = 0; i <= m; ++i) {
        tmp = Solve_fun(d % p, b, p), d = d * base % p;
        if( ~tmp && lg.find(tmp) ) { ans = i * m + lg.posi(tmp) + num; break; }
      }
      return ans;
    }
    
    int main(int argc, const char *argv[])
    {
      u64 a = 0, b = 0, p = 0, ans = 0;
      while( ~scanf("%lld%lld%lld", &a, &p, &b) ) if( p ) {
        ans = Ex_bsgs(a, b, p);
        ~ans ? printf("%lld
    ", ans) : printf("No Solution
    ");
      }
      return 0;
    }
    

     
     —— 我们还会继续与人萍水相逢,为了新的别离。

  • 相关阅读:
    JS正则表达式验证账号、手机号、电话和邮箱
    Asp.Net Mvc导出Excel
    后台截取姓名,只留姓名字带*号覆盖
    后台根据身份证号码截取性别和出生日期
    后台传个变量,前台页面显示对应的中文
    第一次封装JS文件之滚动条
    阿里巴巴17校招测试题目(Jquery解法)
    阿里巴巴17实习生招聘编程题目(JavaScript解法)
    SofewareTesting hw3
    PHP之login
  • 原文地址:https://www.cnblogs.com/nanjoqin/p/10201521.html
Copyright © 2020-2023  润新知