二次剩余
对于素数 p p p 和数 a a a,满足 ( a , p ) = 1 (a,p)=1 (a,p)=1。(注意 a a a 不一定小于 p p p)
若 ∃ x x 2 ≡ a ( m o d p ) \exist_{x}\ x^2\equiv a\pmod p ∃x x2≡a(modp),则称 a a a 是模 p p p 意义下的二次剩余, x x x 称为该二次剩余方程式的解。
否则称 a a a 是模 p p p 意义下的非二次剩余。
特判掉 p = 2 p=2 p=2 的情况,接下来默认 p p p 均为非 2 2 2 质数,即奇素数。
勒让德符号
定义:
(
a
p
)
=
{
0
p
∣
a
1
a
在
(
m
o
d
p
)
意
义
下
是
二
次
剩
余
−
1
a
在
(
m
o
d
p
)
意
义
下
不
是
二
次
剩
余
\Big(\frac{a}{p}\Big)= \begin{cases} 0\quad\quad\quad p\ \big|\ a\\ 1\quad\quad\quad a在\pmod p意义下是二次剩余\\ -1\quad\quad\ a在\pmod p意义下不是二次剩余 \end{cases}
(pa)=⎩⎪⎨⎪⎧0p ∣∣ a1a在(modp)意义下是二次剩余−1 a在(modp)意义下不是二次剩余
欧拉准则
( a p ) ≡ a p − 1 2 ( m o d p ) \Big(\frac ap\Big)\equiv a^{\frac{p-1}2}\pmod p (pa)≡a2p−1(modp)
证明:
-
p ∣ a p\ \big|\ a p ∣∣ a。显然成立。
-
当 a a a 是在模 p p p 意义下的二次剩余。
即 ∃ x x 2 ≡ a ( m o d p ) \exist_x\ x^2\equiv a\pmod p ∃x x2≡a(modp)。
有 ( x 2 ) p − 1 2 ≡ a p − 1 2 ( m o d p ) ⇔ x p − 1 ≡ a p − 1 2 ( m o d p ) (x^2)^\frac{p-1}2\equiv a^\frac{p-1}2\pmod p\Leftrightarrow x^{p-1}\equiv a^\frac{p-1}2\pmod p (x2)2p−1≡a2p−1(modp)⇔xp−1≡a2p−1(modp)。
∵ ( a , p ) = 1 ∴ ( x , p ) = 1 \because (a,p)=1\therefore(x,p)=1 ∵(a,p)=1∴(x,p)=1。
⇒ x p − 1 ≡ 1 ≡ a p − 1 2 ( m o d p ) \Rightarrow x^{p-1}\equiv 1\equiv a^\frac{p-1}2\pmod p ⇒xp−1≡1≡a2p−1(modp)。
-
当 a a a 在模 p p p 意义下不是二次剩余。
则有 ∀ i ∈ [ 1 , p ) i j ≡ a ( m o d p ) \forall_{i\in [1,p)}\ ij\equiv a\pmod p ∀i∈[1,p) ij≡a(modp) 的 j j j 是唯一的,且 j ≠ i j\neq i j=i。
考虑用证明逆元唯一的思路来证明这里的唯一性。反证法。
假设 0 < j 1 < j 2 < p 0<j_1<j_2<p 0<j1<j2<p 满足 i j 1 ≡ i j 2 ≡ a ( m o d p ) ij_1\equiv ij_2\equiv a\pmod p ij1≡ij2≡a(modp)。
则 i ( j 2 − j 1 ) ≡ 0 ( m o d p ) ⇒ p ∣ i ( j 2 − j 1 ) i(j_2-j_1)\equiv 0\pmod p\Rightarrow p\ \big|\ i(j_2-j_1) i(j2−j1)≡0(modp)⇒p ∣∣ i(j2−j1)。
( i , p ) = 1 ⇒ p ∣ ( j 2 − j 1 ) (i,p)=1\Rightarrow p\ \big|\ (j_2-j_1) (i,p)=1⇒p ∣∣ (j2−j1),与 0 < j 2 − j 1 < p ⇒ ( j 2 − j 1 , p ) = 1 0<j_2-j_1<p\Rightarrow (j_2-j_1,p)=1 0<j2−j1<p⇒(j2−j1,p)=1 矛盾。
p − 1 p-1 p−1 是偶数,那么我们考虑可以把这些数两两配对,配出 p − 1 2 \frac{p-1}2 2p−1 对。
即 a p − 1 2 ≡ ( p − 1 ) ! ≡ − 1 ( m o d p ) a^\frac{p-1}2\equiv (p-1)!\equiv -1\pmod p a2p−1≡(p−1)!≡−1(modp)(威尔逊定理)。
换言之:
x 2 ≡ a ( m o d p ) , ( a , p ) = 1 x^2\equiv a\pmod p,(a,p)=1 x2≡a(modp),(a,p)=1。
a p − 1 2 ≡ ± 1 ( m o d p ) a^\frac{p-1}2\equiv \pm 1\pmod p a2p−1≡±1(modp)。
方程有解当且仅当 a p − 1 2 ≡ 1 ( m o d p ) a^\frac{p-1}{2}\equiv 1\pmod p a2p−1≡1(modp)。
Cipolla
lemma
:设
ω
\omega
ω 不是模
p
p
p 的二次剩余,即
̸
∃
x
x
2
≡
ω
(
m
o
d
p
)
\not\exist_x\ x^2\equiv \omega\pmod p
∃x x2≡ω(modp),且
ω
=
t
2
−
a
\omega=t^2-a
ω=t2−a。则
x
=
(
t
+
ω
)
p
+
1
2
x=(t+\sqrt{\omega})^\frac{p+1}2
x=(t+ω)2p+1 是二次剩余方程
x
2
≡
a
(
m
o
d
p
)
x^2\equiv a\pmod p
x2≡a(modp) 的解。
证明:
( t + ω ) p = ∑ i = 0 p ( p i ) t i ( ω ) p − i = t p + ω p 2 + ∑ i = 1 p − 1 ( p i ) t i ( ω ) p − i (t+\sqrt\omega)^p=\sum_{i=0}^{p}\binom pit^i(\sqrt\omega)^{p-i}=t^p+\omega^\frac{p}2+\sum_{i=1}^{p-1}\binom pit^i(\sqrt\omega)^{p-i} (t+ω)p=∑i=0p(ip)ti(ω)p−i=tp+ω2p+∑i=1p−1(ip)ti(ω)p−i。
i ∈ ( 0 , p ) , ( p i ) = p ! i ! ( p − i ) ! i\in(0,p),\binom{p}{i}=\frac{p!}{i!(p-i)!} i∈(0,p),(ip)=i!(p−i)!p!。
组合数是整数, i ! , ( p − i ) ! i!,(p-i)! i!,(p−i)! 里的每个数都 < p <p <p,又 p p p 是奇素数,所以 i ! , ( p − i ) ! i!,(p-i)! i!,(p−i)! 里面均不会筛到 p p p。
所以 p ∣ ( p i ) p\ \big|\ \binom pi p ∣∣ (ip)。也就是说后面的求和在模 p p p 意义下是 0 0 0。
⇒ ( t + ω ) p ≡ t p + ( ω ) p ( m o d p ) \Rightarrow (t+\sqrt\omega)^p\equiv t^p+(\sqrt\omega)^p\pmod p ⇒(t+ω)p≡tp+(ω)p(modp)。
t p + ( ω ) p = t p + ω p − 1 2 ω t^p+(\sqrt\omega)^p=t^p+\omega^\frac{p-1}2\sqrt\omega tp+(ω)p=tp+ω2p−1ω,因为 ω \omega ω 不是模 p p p 意义下的二次剩余,所以 ( ω p ) = − 1 = ω p − 1 2 \Big(\frac \omega p\Big)=-1=\omega^\frac{p-1}2 (pω)=−1=ω2p−1, t p = t p − 1 t ≡ t ( m o d p ) t^p=t^{p-1}t\equiv t\pmod p tp=tp−1t≡t(modp)。
⇒ ( t + ω ) p ≡ t − ω ( m o d p ) \Rightarrow (t+\sqrt\omega)^p\equiv t-\sqrt\omega\pmod p ⇒(t+ω)p≡t−ω(modp)
x 2 ≡ ( t + ω ) p + 1 ≡ ( t + ω ) p ( t + ω ) ≡ ( t − ω ) ( t + ω ) ≡ t 2 − ω ≡ a ( m o d p ) x^2\equiv (t+\sqrt\omega)^{p+1}\equiv(t+\sqrt\omega)^p(t+\sqrt\omega)\equiv(t-\sqrt\omega)(t+\sqrt\omega)\equiv t^2-\omega\equiv a\pmod p x2≡(t+ω)p+1≡(t+ω)p(t+ω)≡(t−ω)(t+ω)≡t2−ω≡a(modp)。
在算法实现中,随机 t t t 后求 ω \omega ω,大约有一半的数都是非二次剩余。期望两次便可求出 x x x。
考虑另一种二次剩余方程: x 2 ≡ a ( m o d p n ) x^2\equiv a\pmod {p^n} x2≡a(modpn),其中 ( a , p ) = 1 (a,p)=1 (a,p)=1, p p p 为奇质数。
先求出 x 2 ≡ a ( m o d p ) x^2\equiv a\pmod p x2≡a(modp) 的一个解 τ \tau τ,有 τ 2 − a = k p ⇒ ( τ 2 − a ) n ≡ k n p n ≡ 0 ( m o d p n ) \tau^2-a=kp\Rightarrow (\tau^2-a)^n\equiv k^np^n\equiv 0\pmod {p^n} τ2−a=kp⇒(τ2−a)n≡knpn≡0(modpn)。
{ ( r + a ) n = f + g a ( r − a ) n = f − g a \begin{cases}(r+\sqrt a)^n=f+g\sqrt{a}\\(r-\sqrt a)^n=f-g\sqrt{a}\end{cases} {(r+a)n=f+ga(r−a)n=f−ga
两个式子的结果答案长相一定可以这么写。
证明:二项式定理展开 ( n i ) τ n − i ( ± a ) i \binom ni\tau^{n-i}(\pm\sqrt{a})^i (in)τn−i(±a)i, ( ± a ) i (\pm\sqrt{a})^i (±a)i 如果 i i i 是偶数,第 i i i 项就在 f f f 里面,否则就在 g g g 里面。
也就是说, ( τ 2 − a ) n ≡ [ ( τ + a ) ( τ − a ) ] n ≡ ( τ + a ) n ( τ − a ) n ≡ ( f + g a ) ( f − g a ) ≡ f 2 − g 2 a ≡ 0 ( m o d p n ) (\tau^2-a)^n\equiv [(\tau+a)(\tau-a)]^n\equiv(\tau+a)^n(\tau-a)^n\equiv(f+g\sqrt{a})(f-g\sqrt{a})\equiv f^2-g^2a\equiv 0\pmod {p^n} (τ2−a)n≡[(τ+a)(τ−a)]n≡(τ+a)n(τ−a)n≡(f+ga)(f−ga)≡f2−g2a≡0(modpn)。
( f , p ) = 1 , ( g , p ) = 1 ⇒ f 2 inv ( g 2 ) ≡ a ( m o d n ) (f,p)=1,(g,p)=1\Rightarrow f^2\text{inv}(g^2)\equiv a\pmod n (f,p)=1,(g,p)=1⇒f2inv(g2)≡a(modn)。
由于 p n p^n pn 不是质数,所以用 exgcd \text{exgcd} exgcd 求逆元即可。
代码
#include <cstdio>
#include <iostream>
#include <ctime>
#include <random>
using namespace std;
#define int long long
int T, n, p, omega;
mt19937 wwl(time(0));
struct complex {
int x, y;
complex(){}
complex( int X, int Y ) { x = X, y = Y; }
complex operator * ( complex v ) {
int ansx = ( x * v.x % p + y * v.y % p * omega % p ) % p;
int ansy = ( x * v.y % p + y * v.x % p ) % p;
return complex( ansx, ansy );
}
};
int qkpow( complex x, int y ) {
complex ans( 1, 0 );
while( y ) {
if( y & 1 ) ans = ans * x;
x = x * x;
y >>= 1;
}
return ans.x;
}
int qkpow( int x, int y, int mod ) {
int ans = 1;
while( y ) {
if( y & 1 ) ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans;
}
int cipolla( int n, int p ) {
n %= p;
if( p == 2 ) return n;
if( qkpow( n, p - 1 >> 1, p ) == p - 1 ) return -1;
int t;
while( 1 ) {
t = wwl() % p;
omega = ( ( t * t % p - n ) % p + p ) % p;
if( qkpow( omega, p - 1 >> 1, p ) == p - 1 ) break;
}
complex ans( t, 1 );
return qkpow( ans, p + 1 >> 1 );
}
signed main() {
scanf( "%lld", &T );
while( T -- ) {
scanf( "%lld %lld", &n, &p );
if( n == 0 ) { puts("0"); continue; }
int ans = cipolla( n, p );
if( ! ~ ans ) { puts("Hola!"); continue; }
if( ans == p - ans ) printf( "%lld\n", ans );
else printf( "%lld %lld\n", min( ans, p - ans ), max( ans, p - ans ) );
}
return 0;
}