1. 程式人生 > >[拓展Bsgs] Clever - Y

[拓展Bsgs] Clever - Y

題目連結 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\n", ans) : printf("No Solution\n");
  }
  return 0;
}

 
 —— 我們還會繼續與人萍水相逢,為了新的別離。