zoukankan      html  css  js  c++  java
  • 幂方程(模意义下)

    问题

    求解 $$x^aequiv b(mod p)$$

    其中 $p$ 为质数

    分析

    由于 $p$ 为质数,肯定存在原根 $g$。

    由原根的定义知 $x$ 可表示成 $x=g^c$,问题转化为 $(g^c)^a equiv b(mod p)$,得到

    $$(g^a)^c equiv b(mod p)$$

    于是就转换成我们熟悉的BSGS模型了,可以在 $O(sqrt p logp)$ 解出 $c$。

    这样得到原方程的一个特解 $x_0 equiv g^c(mod p)$。显然,这个解不一定是最小解。

    如何求出最小解呢?

    由于存在取模操作,需要求出所有解。

    如何求出所有解呢?

    已知 $x0=g^c$ 为其中一个解,设另外一个解 $g^{c+ delt}$ ,有

    $$(g^{c+delt})^a equiv b(mod p)$$

    推出 $g^{deltcdot a} equiv 1(mod p)$,进一步有 $delt cdot a mid varphi (p)$,所以 $delt$ 最小为 $delt = frac{varphi (p)}{gcd(a, varphi (p))}$.

    易知,$g^{c+k * delt}$ 都是方程的解。 

    //下面贴出求所有解的模板,注意可能爆int!!

    int gcd(int a, int b) { return a ? gcd(b % a, a) : b; }
    int powmod(int a, int b, int p) {
      int res = 1;
      while (b > 0) {
        if (b & 1) res = res * a % p;
        a = a * a % p, b >>= 1;
      }
      return res;
    }
    // Finds the primitive root modulo p
    int generator(int p) {
      vector<int> fact;
      int phi = p - 1, n = phi;
      for (int i = 2; i * i <= n; ++i) {
        if (n % i == 0) {
          fact.push_back(i);
          while (n % i == 0) n /= i;
        }
      }
      if (n > 1) fact.push_back(n);
      for (int res = 2; res <= p; ++res) {
        bool ok = true;
        for (int factor : fact) {
          if (powmod(res, phi / factor, p) == 1) {
            ok = false;
            break;
          }
        }
        if (ok) return res;
      }
      return -1;
    }
    // This program finds all numbers x such that x^k=a (mod n)
    int main() {
      int n, k, a;
      scanf("%d %d %d", &n, &k, &a);
      if (a == 0) return puts("1
    0"), 0;
      int g = generator(n);
      // Baby-step giant-step discrete logarithm algorithm
      int sq = (int)sqrt(n + .0) + 1;
      vector<pair<int, int>> dec(sq);
      for (int i = 1; i <= sq; ++i)
        dec[i - 1] = {powmod(g, i * sq * k % (n - 1), n), i};
      sort(dec.begin(), dec.end());
      int any_ans = -1;
      for (int i = 0; i < sq; ++i) {
        int my = powmod(g, i * k % (n - 1), n) * a % n;
        auto it = lower_bound(dec.begin(), dec.end(), make_pair(my, 0));
        if (it != dec.end() && it->first == my) {
          any_ans = it->second * sq - i;
          break;
        }
      }
      if (any_ans == -1) return puts("0"), 0;
      // Print all possible answers
      int delta = (n - 1) / gcd(k, n - 1);
      vector<int> ans;
      for (int cur = any_ans % delta; cur < n - 1; cur += delta)
        ans.push_back(powmod(g, cur, n));
      sort(ans.begin(), ans.end());
      printf("%d
    ", ans.size());
      for (int answer : ans) printf("%d ", answer);
    }

    参考链接:https://oi-wiki.org/math/bsgs/

  • 相关阅读:
    STDMETHOD (转)
    DirectX中的纹理映射相关技术 (转)
    (转)清空std::stringstream,联系到stream的clear()和清空
    (转载)MultiAnimation
    (转)SkyBox
    [转载]漫谈游戏中的阴影技术
    反射矩阵计算
    (转)COM组件里的AddRef()
    LINQ简记(2):重要概念
    继续聊WPF——自定义命令
  • 原文地址:https://www.cnblogs.com/lfri/p/11509443.html
Copyright © 2011-2022 走看看