二次剩余

二次剩余,就是求解方程

\[x^2\equiv n (\mod p) \]

此时\(p\)为一个奇素数,就是常规的二次剩余问题

根的数量

我们假设一个方程有多个根那么可以列出\(x_0^2\equiv x_1^2(\mod p)\)

移项之后可得\((x_1-x_0)(x_1+x_0)\equiv0(\mod p)\)

因为\(x_0\),\(x_1\)为两不同的根所以\(x_1-x_0\)\(p\)不会为\(0\)

所以\(x_1+x_0\equiv0(\mod p)\),即\(x_0\),\(x_1\)为相反数

因为\(p\)为奇素数,所以两根肯定不相同,所以方程必然有两不同根

欧拉准则

那么我们现在解决判断\(n\)是否在模\(p\)的意义下为二次剩余的问题

先放结论\(n^{\frac{p-1}2}\equiv 1(\mod p)\)\(n\)为模\(p\)意义下的二次剩余的充要条件

先证明必要性,由于\(n\)为二次剩余由\(x^{p-1}\equiv 1(\mod p)\)可知\((x^2)^{\frac{p-1}2}=n^{\frac{p-1}2}\equiv 1(\mod p)\)

再证明充分性,\(n=g^k\),其中\(g\)为原根,那么\(g^{k\frac{p-1}{2}}\equiv 1(\mod p)\),由于原根一定不为二次剩余,所以\(p-1|k\frac{p-1}2\)所以\(k\)必然为偶数,那么\(g^{\frac k2}\)即为\(n\)的二次剩余。

那么我们便证明了\(n^{\frac{p-1}2}\equiv 1(\mod p)\)\(n\)为模\(p\)意义下的二次剩余是等价的

因为\(n^{p-1}\equiv 1(\mod p)\)所以\(n^{\frac{p-1}2}\)\(1\)的二次剩余为\(1\)\(-1\),所以若\(n\)是二次剩余,\(n^{\frac{p-1}2}\)的值为\(-1\)

Cipolla

我们现在考虑解方程\(x^2\equiv n\)

首先找到一个\(a\)满足\(a^2-n\)是非二次剩余,期望是\(2\)次即可找到

接下来定义\(i^2\equiv a^2-n\),这里的\(i\)的定义类似于单位虚数的定义。

然后可以把所有数表示为\(A+Bi\)的形式。

那么我们可以有两个结论

引理1\(i^p\equiv-i\)

证明:\(i^p\equiv i(i^2)^{\frac{p-1}2}\equiv i(a^2-n)^{\frac{p-1}2}\equiv-i\)

引理2\((A+B)^p\equiv A^p+B^p\)

证明:由二项式定理,由于\(p\)为质数,除了\(C_p^0\),\(C_p^p\)外的组合数分子上的阶乘没法消掉,模\(p\)\(0\),只剩\(C_p^0A^p+C_p^pB^p\)

最后我们就可以得出结论\((a+i)^{p+1}\equiv n\)

证明:

\[(a+i)^{p+1}\equiv(a^p+b^p)(a+i)\equiv(a-i)(a+i)\equiv a^2-i^2\equiv n \]

那么\(\pm(a+i)^{\frac{p+1}2}\)就是方程的解

code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
struct Com{LL r,i;};
LL w;
Com mul(Com a,Com b,LL P){
	Com c;
	c.r=(a.r*b.r%P+a.i*b.i%P*w%P)%P;
	c.i=(a.r*b.i%P+a.i*b.r%P)%P;
	return c;
}
LL fpowr(LL a,LL b,LL P){LL ret=1;
	for(;b;b>>=1,a=a*a%P)
	if(b&1)ret=ret*a%P;
	return ret;
}
Com fpowc(Com a,LL b,LL P){Com ret={1,0};
	for(;b;b>>=1,a=mul(a,a,P))
	if(b&1)ret=mul(ret,a,P);
	return ret;
}
LL Euler(LL n,LL P){
	return fpowr(n,P-1>>1,P);
}
LL solve(LL n,LL P){
	n%=P;
	LL a;do a=rand()%P;
	while(Euler(w=(a*a%P-n+P)%P,P)!=P-1);
	return fpowc({a,1},P+1>>1,P).r;
}
int main(){
	srand(time(NULL));
	int T;scanf("%d",&T);
	while(T--){
		LL n,P,a,b;
		scanf("%lld%lld",&n,&P);
		if(!n){puts("0");continue;}
		if(Euler(n,P)==P-1){puts("Hola!");continue;}
		else{
			a=solve(n,P),b=P-a;
			if(a>b)swap(a,b);
			printf("%lld %lld\n",a,b);
		}
	}
	return 0;
}
posted @ 2023-08-17 08:41  董哲仁  阅读(58)  评论(0)    收藏  举报