二次剩余
本文参考 OI-wiki.
下文中,
使得
一些性质
-
在
1, \dots, p-1 中恰有一半,即\frac{p - 1}{2} 个二次剩余。设
g 是\mathbb{F}_p 的原根,则二次剩余恰为1,g^2,g^4,\dots,g^{p-3} 另一个证明:如果
x^2 \equiv y^2 ,那么p|(x+y)(x-y) ,所以x \equiv \pm y . 于是二次剩余恰为1^2,2^2,\dots,\left(\frac{p-1}{2}\right)^2 ,并且这些两两不同。 -
考虑 $x=g^u,y=g^v$,那么相当于说 $u+v$ 是偶数当且仅当 $u,v$ 都是偶数或者都是奇数。 -
令
\left(\frac{a}{p}\right) (Legendre symbol)为:0 & a \equiv 0 \\ 1 & a \text{是二次剩余} \\ -1 & a \text{不是二次剩余} \end{cases} 则
\left(\frac{a}{p}\right) \equiv a^{(p-1) / 2} 。如果
a = g^u ,那么a^{(p-1) / 2} = g^{u(p-1) / 2} ,而这个数等于\pm1 ;u 为奇数,即a 不是二次剩余的时候,a^{(p-1)/2} = -1 ;否则a^{(p-1)/2} = 1 。这样我们还可以得出:
\left(\frac{a}{p}\right)\left(\frac{b}{p}\right)=\left(\frac{ab}{p}\right) -
二次互反律:若
q 是另一个奇素数,那么\left(\frac{q}{p}\right)\left(\frac{p}{q}\right)=(-1)^{(p-1)(q-1)/4} 另外,
\left(\frac{-1}{p}\right)=(-1)^{(p-1)/2}\quad \left(\frac{2}{p}\right)=(-1)^{(p^2-1)/8} 在 OI 中很少用到,证明比较麻烦,此处略去。
Cipolla 算法
给定
首先我们找到一个
这一步没有什么高效的办法,可以随机
不妨设
n \equiv b^2 。那么a^2-b^2=(a+b)(a-b) 不是二次剩余当且仅当\frac{a+b}{a-b} 不是二次剩余。可以发现a 在除b 以外的数([0,p) 以内)之间遍历一遍的时候\frac{a+b}{a-b} 在1 以外的数遍历了一遍。从而恰有\frac{p-1}{2} 个a 使得a^2-b^2 不是二次剩余。
接下来考虑扩域
也就是所有形如
在这个扩域中,我们有一些性质:
-
这是因为 $(x+y)^p = \sum_{k = 0}^p \binom{p}{k} x^k y^{p-k}$, 而当 $0 < k < p$ 的时候 $\binom{p}{k}$ 被 $p$ 整除。 -
因为 $\alpha^p = (a^2-n)^{(p - 1)/2} \alpha = -\alpha$。 - 如果
x \in \mathbb{F}_p ,那么仍然有x^p = x 。 因为\mathbb{F}_p 里有x^p = x ,并且嵌入到新的域里面之后乘法法则没有变。
现在令
那么
于是我们在
然而域里面的
(类比一下,如果
在代码实现中,选好
代码实现
typedef long long LL;
int p, l;
struct F2 {
int u, v;
F2(int u = 0, int v = 0) : u(u), v(v) {}
friend F2 operator*(const F2 &a, const F2 &b) {
LL u = (LL)a.u * b.u + (LL)a.v * b.v % p * l;
LL v = (LL)a.u * b.v + (LL)a.v * b.u;
return F2(u % p, v % p);
}
};
LL pow_mod(LL a, int b) {
LL ans = 1;
for (a %= p; b; b >>= 1, a = a * a % p)
if (b & 1) ans = ans * a % p;
return (ans + p) % p;
}
F2 pow_mod2(F2 a, int b) {
F2 ans(1, 0);
for (; b; b >>= 1, a = a * a)
if (b & 1) ans = ans * a;
return ans;
}
LL Cipolla(LL n) {
LL a = 0;
while (pow_mod(a * a - n, (p - 1) / 2) != p - 1)
a = rand() % p;
l = (a * a - n) % p;
if (!l) return a;
return (pow_mod2(F2(a, 1), (p + 1) / 2).u + p) % p;
}