• 幂方程(模意义下)


    问题

    求解 $$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/

  • 相关阅读:
    flash中网页跳转总结
    as3自定义事件
    mouseChildren启示
    flash拖动条移出flash无法拖动
    需要一个策略文件,但在加载此媒体时未设置checkPolicyFile标志
    Teach Yourself SQL in 10 Minutes
    电子书本地转换软件 Calibre
    Teach Yourself SQL in 10 Minutes
    Teach Yourself SQL in 10 Minutes
    Teach Yourself SQL in 10 Minutes – Page 31 练习
  • 原文地址:https://www.cnblogs.com/lfri/p/11509443.html
Copyright © 2020-2023  润新知