版权声明:我是一只蒟蒻,欢迎大家批评建议 https://blog.csdn.net/stevensonson/article/details/85845334
二次剩余是数论基本概念之一,它是初等数论中非常重要的结果。
什么是二次剩余呢?简单来说就是如果存在一个整数
x,使得
x2≡n(mod p),那么则称
n是模
p的二次剩余。
有一种很巧妙的办法,可以得出一个数是否是模
p的二次剩余。这个办法是勒让德符号
(pn)。
如果
n是模
p的二次剩余,那么
(pn)=1;
如果
n不是模
p的二次剩余,那么
(pn)=−1;
如果
p∣n,则
(pn)=0
这里有一个结论:
(pn)=n2p−1 (前提是
p是奇质数)
证明:(不看也无所谓)
①如果
n是模
p的二次剩余,那么
n
与
p互质,那么根据费马小定理
(n
)p−1≡1(mod p)。
②如果
n不是模
p的二次剩余,那么因为
p是奇质数,所以根据扩欧可知对于
i∈[1,p−1],都有一个
j∈[1,p−1]使其满足
ij≡n(mod p)。所以我们可以把
1,2……p−1分成
2p−1对,每对的乘积在模
p下都是
n,那么
(p−1)!≡n2p−1(mod p),根据威尔逊定理有
(p−1)!≡−1(mod p),所以
n2p−1≡−1(mod p)
③如果
p∣n,那么显然
n2p−1≡0(mod p)
定理:对于方程
x2≡n(mod p),有
2p−1个不同的
n,使得该方程有解。
证明:若有两个数
u和
v均满足它们的平方在
p时同余,那么必然有
p∣(u+v)(u−v)。由于
p不可能整除
u−v,那么可以得出
p整除
u+v。这个结论反过来也是成立的,因此共有
2p−1种不同的平方。且每一个
p的二次剩余恰好有两个解。
那么怎么求一个二次剩余呢?我们可以按照下面的方法:
在
[0,p−1]随机挑选一个数,称其为
a,定义
w=a2−n,若
(pw)=−1,那么
(a+w
)2p+1就是一组二次剩余。
证明:
(a+w
)p=∑i=0p(Cpiap−i)(Cpp−i(w
)i),由于
p是质数,所以除了
Cp0和
Cpp为
1外,所有的
Cpi(i∈[1,p−1])模
p等于
0,所以
(a+w
)p≡ap+w
p (mod p)。
由费马小定理可得
ap≡a(mod p),又因为
(pw)=−1即
w2p−1=−1,所以
w
p=−w
所以
(a+w
)p≡ap+w
p (mod p)≡a−w
(mod p)
所以
(a+w
)p+1≡(a+w
)p(a+w
)≡(a−w
)(a+w
)≡a2−w≡n
有了最后一个定理,我们就可以通过随机选择a的值来找到一个满足条件的解。可以证明找到正解所需的次数的期望只有2(然而我并不是特别会证)。所以随机取a的值可以很快地找到一个解。
部分代码:
struct field{
int x,y;
field(int a=0,int b=0){
x=a;y=b;
}
};
field operator*(field a,field b){return field(a.x*b.x%p+a.y*b.y%p*w%p,a.x*b.y%p+a.y*b.x%p);}
int ran(){
static int seed=23333;
return seed=((((((ll)seed^20030927)%p+330802)%p*9410)%p-19750115+p)%p^730903)%p;
}
int pows(int a,int b){
int base=1;
while(b){
if(b&1) base=base*a%p;
a=a*a%p;b/=2;
}
return base;
}
field powfield(field a,int b){
field base=field(1,0);
while(b){
if(b&1) base=base*a;
a=a*a;b/=2;
}
return base;
}
int legander(int x){
int a=pows(x,(p-1)/2);
if(a+1==p) return -1;
return a;
}
int surplus(int x){
int a;
if(legander(x)==-1) return 0;
while(1){
a=ran()%p;
w=((a*a-x)%p+p)%p;
if(legander(w)==-1) break;
}
field b=field(a,1);
b=powfield(b,(p+1)/2);
return b.x;
}