二次剩余总结

为了方便,所有同余号都写成等号。

定义

如果对于 \(n\)\(n\) 不是 \(p\) 的倍数, 且存在 \(x\) 使得 \(x^2 = n \mod p\) , 则称 \(n\) 为模 \(p\) 意义下的二次剩余, 如果 \(n\) 不是 \(p\) 的倍数, 却不是模 \(p\) 意义下的二次剩余,则 \(n\) 为模 \(p\) 意义下的非二次剩余。

性质

二次剩余的数量

结论 : 在模 \(p\) 意义下,有 \(\frac{p - 1}{2}\) 个二次剩余和 \(\frac{p - 1}{2}\) 个非二次剩余. (不包括 0)

对于一个二次剩余 \(n\) , 设 \(x^2=n\)

对于任意两个不相等的解 \(x_0, x_1\) , 有 \(x_0^2 = x_1^2\) , 移项有 \(x_0^2-x_1^2=(x_0+x_1)(x_0-x_1) = 0\) .

因为 \(x_0 \neq x_1\) , 所以 \(x_0 - x_0 \neq 0\), 所以 \(x_0 + x_1 = 0\) , 所以任意一个二次剩余的解是一对相反数。当 \(p\) 为奇素数时两个相反数不会相等。因为奇偶性不同。

所以任意一对相反数都一一对应一个二次剩余。所以二次剩余数量为 \(\frac{p-1}{2}\) , 相对应的非二次剩余数量为 \((p - 1) - \frac{p-1}{2} = \frac{p - 1}{2}\)

欧拉判别准则

\(n\) 是二次剩余,当且仅当 \(n^{\frac{p-1}{2}} = 1\)
\(n\) 是非二次剩余,当且仅当 \(n^{\frac{p-1}{2}} = -1\)

证明:

因为 \(n^{p-1}=1\) , 由于 \(p\) 是奇素数, 所以有 \(n^{p - 1}- 1 = (n^{\frac{p-1}{2}} + 1)(n^{\frac{p-1}{2}} -1 )= 0\) , 所以 \(n^{\frac{p-1}{2}} = \pm 1\)

\(n\) 是二次剩余则 \(n^{\frac{p-1}{2}} = (x^2)^{\frac{p-1}{2}}=x^{p-1}=1\)

\(n^{\frac{p-1}{2}}=1\) , 则将 \(n\) 表示为 \(g^k\) , 那么有 \(g^{k\frac{p-1}{2}} = 1\) , 根据原根的阶是 \(\varphi(p)\) , 有 \((p - 1)| k\frac{p-1}{2}\) , 所以 \(2 | k\) , 所以 \(n\) 开根为 \(g^{\frac{k}{2}}\) , \(n\) 是二次剩余。

那么 \(n\) 是非二次剩余等价于 \(n^\frac{p-1}{2}=-1\)

Cipolla 算法

用来在模 \(p\) ( \(p\) 是质数) 意义下,对一个二次剩余开根

找到一个 \(a\) 使得 \(a^2 - n\) 是非二次剩余。 因为非二次剩余一共有 \(\frac{p - 1}{2}\) 个,所以期望 \(2\) 次就能找到。

考虑拓域, 设 \(i^2 = a^2 - n\) , 每个数都能表示成 \(A +Bi\) .

有定理 \((a+i)^{p+1} = n\)

引理 1:

\(i^p=-i\)

证明:

\(i^p = (i^2)^{\frac{p-1}{2}}\cdot i = (a^2 - n)^{\frac{p-1}{2}}\cdot i = -i\)

引理 2:

\(p\) 是素数时

\[\tbinom{p}{k}= [k=0] + [k=p] \mod p \]

因为 \(p\) 是素数, 且 \(k \neq 0,k\neq p\) , 所以 \(\tbinom{p}{k}\) 分子中的 \(p\) 不会被分母中的数整除。所以 \(\tbinom{p}{k}\)\(0\)

引理 3:

\((a+b)^p = a^p + b^p\)

证明:

\((a+b)^p = \sum_{i=0}^{p} \tbinom{p}{i}a^pb^{p-i} = a^p + b^p\)

证明 :

\[\begin{aligned} (a+i)^{p+1} &= (a+i)(a+i)^p\\ &=(a+i)(a^p+i^p)\\ &=(a+i)(a-i)\\ &=a^2-(a^2-n)\\ &=n \end{aligned} \]

既然 \((a+i)^{p+1} = n\) , 那么显然 \((a+i)^{\frac{p+1}{2}} = \sqrt{n}\) 。 所以 \(n\) 的平方根为 \((a+i)^{\frac{p+1}{2}}\)\(p-(a+i)^{\frac{p+1}{2}}\)

代码

#include <iostream>
#include <cstdio>
#define int long long

using namespace std;

int T;
int n, mod;
int I;

struct Complex {
  int x, y;
  Complex (int _x = 0, int _y = 0) {
    x = _x, y = _y;
  }

  friend Complex operator + (Complex &a, Complex &b) {
    return Complex((a.x + b.x) % mod, (a.y + b.y) % mod);
  }

  friend Complex operator * (Complex &a, Complex &b) {
    return Complex((a.x * b.x % mod + a.y * b.y % mod * I % mod) % mod, (a.x * b.y % mod + a.y * b.x % mod) % mod);
  }

  friend Complex operator % (Complex &a, int b) {
    return Complex(a.x % b, a.y % b);
  }
};


Complex qpow(Complex a, int b) {
  Complex res(1, 0);
  while (b) {
    if (b & 1) res = res * a;
    a = a * a;
    b >>= 1;
  }
  return res;
}

int qpow(int a, int b) {
  int res = 1;
  while (b) {
    if (b & 1) res = res * a % mod;
    a = a * a % mod;
    b >>= 1;
  }
  return res;
}

signed main() {
  scanf("%lld", &T);
  while (T--) {
    scanf("%lld%lld", &n, &mod);
    if (qpow(n, (mod - 1) / 2) == mod - 1) {
      puts("Hola!");
      continue;
    }
    if (n == 0) {
      puts("0");
      continue;
    }
    int a = rand() % mod;
    while (!a || qpow((a * a % mod + mod - n) % mod, (mod - 1) / 2) != mod - 1) {
      a = rand() % mod;
    }
    I = (a * a % mod + mod - n) % mod;
    int ans1 = qpow(Complex(a, 1), (mod + 1) / 2).x % mod;
    int ans2 = mod - ans1;
    if (ans1 == ans2) {
      printf("%lld\n", ans1);
    }
    else {
      printf("%lld %lld\n", min(ans1, ans2), max(ans1, ans2));
    }
  }
  return 0;
}
posted @ 2021-12-12 21:35  youwike  阅读(130)  评论(0编辑  收藏  举报