二次剩余是数论基本概念之一。它是初等数论中非常重要的结果。俗称模意义开根。
二次剩余定义:若存在整数 x x x,对于整数 d d d 满足 x 2 ≡ a ( m o d p ) x^2\equiv a\pmod{p} x2≡a(modp),称 a a a 是模 p p p 意义下的二次剩余。
下面探讨 p p p 为奇素数的情况(因为 p = 2 p=2 p=2 时没什么意义)。使用 Cipolla \text{Cipolla} Cipolla 算法求解。
当 a = 0 a=0 a=0 时显然 x = 0 x=0 x=0,下面就不讨论了。
设 x 1 ≠ x 2 x_1\not=x_2 x1=x2,且 x 1 , x 2 x_1,x_2 x1,x2 都是方程的根。
则有 x 1 2 − x 2 2 ≡ 0 ( m o d p ) x_1^2-x_2^2\equiv0\pmod p x12−x22≡0(modp)
变形得到 ( x 1 + x 2 ) ( x 1 − x 2 ) ≡ 0 ( m o d p ) (x_1+x_2)(x_1-x_2)\equiv0\pmod p (x1+x2)(x1−x2)≡0(modp)
x 1 − x 2 x_1-x_2 x1−x2 自然不等于零,所以有 x 1 + x 2 = 0 x_1+x_2=0 x1+x2=0
据此,容易证得方程的不同根最多只有两个。
意思是 x 2 ≡ d ( m o d p ) x^2\equiv d\pmod p x2≡d(modp) 的根只有两个,且互为相反数。
一个二次剩余对应两个不同的根,还是互为相反数。在模意义下可以找到 p − 1 2 \dfrac{p-1}{2} 2p−1 对相反数,则 p p p 有 p − 1 2 \dfrac{p-1}{2} 2p−1 个二次剩余,自然 p p p 有 p − 1 2 \dfrac{p-1}{2} 2p−1 个非二次剩余。
勒让德符号定义如下
( a p ) = { 1 a 是 p 的二次剩余 − 1 a 是 p 的非二次剩余 0 a ≡ 0 ( m o d p ) \left(\dfrac{a}{p}\right)= \begin{cases}1&\text{a 是 p 的二次剩余}\\ -1&\text{a 是 p 的非二次剩余}\\ 0&a\equiv0\pmod p\\ \end{cases} (pa)=⎩ ⎨ ⎧1−10a 是 p 的二次剩余a 是 p 的非二次剩余a≡0(modp)
欧拉准则: ( a p ) = a p − 1 2 \left(\dfrac{a}{p}\right)=a^{\frac{p-1}2} (pa)=a2p−1
证明:
由费马小定理得 a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv1\pmod p ap−1≡1(modp)
式子变换得到 ( a p − 1 2 + 1 ) ( a p − 1 2 − 1 ) ≡ 0 ( m o d p ) (a^{\frac{p-1}2}+1)(a^{\frac{p-1}2}-1)\equiv0\pmod p (a2p−1+1)(a2p−1−1)≡0(modp)
所以 a p − 1 2 a^{\frac{p-1}2} a2p−1 等于 1 1 1 或 − 1 -1 −1
提出命题:「 a a a 是 p p p 的二次剩余」是「 a p − 1 2 ≡ 1 ( m o d p ) a^{\frac{p-1}2}\equiv1\pmod p a2p−1≡1(modp)」的充要条件。
因为「 a a a 是 p p p 的二次剩余」是「 a p − 1 2 ≡ 1 ( m o d p ) a^{\frac{p-1}2}\equiv1\pmod p a2p−1≡1(modp)」的充要条件,自然 「 a a a 是 p p p 的二次非剩余」是「 a p − 1 2 ≡ − 1 ( m o d p ) a^{\frac{p-1}2}\equiv-1\pmod p a2p−1≡−1(modp)」的充要条件,而若 a ≡ 0 ( m o d p ) a\equiv0\pmod p a≡0(modp),对应勒让德符号为 0 0 0。综上,欧拉准则得证。
若 p p p 为奇素数,求二次剩余可用 Cipolla \text{Cipolla} Cipolla 算法。
算法流程:找出一个 x x x,使 x 2 − a x^2-a x2−a 是 p p p 的二次非剩余。然后令 i 2 ≡ x 2 − a ( m o d p ) i^2\equiv x^2-a\pmod p i2≡x2−a(modp),则 ( x + i ) p + 1 2 (x+i)^{\frac{p+1}2} (x+i)2p+1 为方程的一个根,其相反数为方程的另一个根。
???
x 2 − a x^2-a x2−a 不是二次非剩余呢,怎么会存在一个 i i i 使 i 2 i^2 i2 等于它呢?
类似于复数,这里的 i i i 是一个“虚数单位”。我们对实数进行数域扩充,所有数都能表示成 a + b i a+bi a+bi 的形式,其中 a , b a,b a,b 为实数。
下面证明 Cipolla \text{Cipolla} Cipolla 算法的正确性:
由二项式定理可得:
( x + i ) p ≡ ∑ j = 0 p C p j x j i p − j ( m o d p ) ≡ ∑ j = 0 p p ! j ! ( p − j ) ! x j i p − j ( m o d p ) \begin{aligned} (x+i)^{p}&\equiv\sum\limits_{j=0}^{p}C_p^jx^ji^{p-j}\pmod p\\ &\equiv\sum\limits_{j=0}^p\dfrac{p!}{j!(p-j)!}x^ji^{p-j}\pmod p \end{aligned} (x+i)p≡j=0∑pCpjxjip−j(modp)≡j=0∑pj!(p−j)!p!xjip−j(modp)
观察 C p j C_p^j Cpj 发现只有 j j j 取 0 0 0 或 p p p 时等于 1 1 1,取其他值时模 p p p 为 0 0 0。
则
( x + i ) p ≡ x p + i p ( m o d p ) (x+i)^{p}\equiv x^p+i^p\pmod p (x+i)p≡xp+ip(modp)
那么
( x + i ) p + 1 ≡ ( x + i ) ( x + i ) p ( m o d p ) ≡ ( x + i ) ( x p + i p ) ( m o d p ) \begin{aligned} (x+i)^{p+1}&\equiv(x+i)(x+i)^p\pmod p\\ &\equiv(x+i)(x^p+i^p)\pmod p \end{aligned} (x+i)p+1≡(x+i)(x+i)p(modp)≡(x+i)(xp+ip)(modp)
根据费马小定理, x p ≡ x ( m o d p ) x^p\equiv x\pmod p xp≡x(modp)。
对 i p i^p ip 进行变形
i p ≡ i 2 ⋅ p − 1 2 ⋅ i ≡ ( x 2 − a ) p − 1 2 i ( m o d p ) i^p\equiv i^{2\cdot\frac{p-1}2}\cdot i\equiv(x^2-a)^{\frac{p-1}2}i\pmod p ip≡i2⋅2p−1⋅i≡(x2−a)2p−1i(modp)
由于 x 2 − a x^2-a x2−a 是 p p p 的非二次剩余,所以 ( x 2 − a ) p − 1 2 ≡ − 1 ( m o d p ) (x^2-a)^{\frac{p-1}2}\equiv-1\pmod p (x2−a)2p−1≡−1(modp)
可得 i p ≡ − i ( m o d p ) i^p\equiv-i\pmod p ip≡−i(modp)
则
( x + i ) p + 1 ≡ x 2 − i 2 ≡ a ( m o d p ) (x+i)^{p+1}\equiv x^2-i^2\equiv a\pmod p (x+i)p+1≡x2−i2≡a(modp)
所以 ( x + i ) p + 1 2 (x+i)^{\frac{p+1}2} (x+i)2p+1 是方程的根。
分析时间复杂度,因为质数 p p p 有 p − 1 2 \dfrac{p-1}{2} 2p−1 个非二次剩余,所以找 x x x 期望 2 2 2 次找到。后面用了一次快速幂求答案。总的时间复杂度为 O ( log p ) O(\log p) O(logp)
在实现中可以使用类似于复数的方式求 ( x + i ) p + 1 2 (x+i)^{\frac{p+1}2} (x+i)2p+1。
定义一个“复数”类型 special complex \text{special complex} special complex。
对于两个“复数” x 1 + y 1 i , x 2 + y 2 i x_1+y_1i,x_2+y_2i x1+y1i,x2+y2i,二者的乘积为 x 1 x 2 + y 1 y 2 i 2 + ( x 1 y 2 + y 1 x 2 ) i x_1x_2+y_1y_2i^2+(x_1y_2+y_1x_2)i x1x2+y1y2i2+(x1y2+y1x2)i。
因为 i 2 ≡ x 2 − a i^2\equiv x^2-a i2≡x2−a 的,这样就得出“复数”乘法的运算规则了。
具体实现如下
#include
using namespace std;
typedef long long ll;
ll n,mod,sqri;
struct special_complex
{
ll a,b;
special_complex(){}
special_complex(ll x,ll y){a=x,b=y;}
special_complex operator*(const special_complex &x){
return special_complex((a*x.a+b*x.b%mod*sqri)%mod,(a*x.b+b*x.a)%mod);
}
};
special_complex ksm(special_complex a,ll b)
{
special_complex ans=special_complex(1,0);
while(b){
if(b&1) ans=ans*a;
b>>=1;
a=a*a;
}
return ans;
}
ll ksm(ll a,ll b)
{
ll ans=1;
while(b){
if(b&1) ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans;
}
ll get_quadratic_residue(ll n,ll mod)
{
if(ksm(n,mod>>1)==mod-1) return -1;
ll t=1ll*rand()*rand()%mod;
while(ksm((t*t-n)%mod+mod,mod>>1)==1) t=1ll*rand()*rand()%mod;
sqri=((t*t-n)%mod+mod)%mod;
return ksm(special_complex(t,1),mod+1>>1).a;
}
int main()
{
int t;
cin>>t;
while(t--){
scanf("%lld%lld",&n,&mod);
if(!n){puts("0");continue;}
ll rt=get_quadratic_residue(n,mod);
if(rt==-1){puts("Hola!");continue;}
rt=min(rt,mod-rt);
printf("%lld %lld\n",rt,mod-rt);
}
}