二次剩余

二次剩余

PS:以下内容大概都是抄的。
大概是解这样一个方程:

\[x^2 \equiv n \pmod p \]

 
这里讨论 \(p\) 为奇素数。

称非 \(0\)\(n\) 是二次剩余当 \(n\) 存在上述方程的解,反之成为非二次剩余。

二次剩余的数量为 \(\frac{p-1}{2}\),原因是这样的:

1.若一个数 \(n\) 为二次剩余,设它有两组解,\(x_1,x_2\)
那么 \(x_1^2 \equiv x_2^2 \equiv n\),由平方差公式得到 \((x_1-x_2)(x_1+x_2) \equiv 0\)
那么 \(x_1 \equiv -x_2\),因为 \(p\) 为奇素数,所以 \(x_1 \neq x_2\)

2.若 \(n\) 为二次剩余,存在解 \(x\)\(-x\) 也为解。

欧拉准则

大概是判断一个数 \(n\) 是否是二次剩余。

做法是这样的,求 \(n^{\frac{p-1}{2}}\),若为 \(1\) 则是,否则不是。

首先有这样一个事情,\(n^{p-1} \equiv 1\),则 \((n^{\frac{p-1}{2}})^2 \equiv 1\)
若其取值为 \(1\),可以令 \(n=g^k\),其中 \(g\) 为原根。
则有 \(g^{k\frac{p-1}{2}} \equiv 1\),即 \((p-1)| k\frac{p-1}{2}\)
\(2|k\),所以 \(n\) 为二次剩余。

然后还有这样一个事情,若 \(n\) 为二次剩余,则存在 \(x^2 \equiv n\)
\(n^{\frac{p-1}{2}}\equiv x^{p-1} \equiv 1\)
所以 \(n^{\frac{p-1}{2}}\equiv 1\)\(n\) 是二次剩余是等价的条件。

故可以通过 \(n^{\frac{p-1}{2}}\)\(1\)\(-1\) 来判断 \(n\) 是否为二次剩余。

Cipolla

大概是对于 \(n\) 为二次剩余,找到 \(x\) 满足 \(x^2 \equiv n\)

做法是这样的,首先找到一个 \(a\),满足 \(a^2-n\) 为非二次剩余,这个过程通过随机并检验即可实现。
定义一个类似虚部的东西 \(i\),满足 \(i^2 \equiv a^2-n\)
然后有 \((a+i)^{p+1} \equiv n\)\((a+i)^{\frac{p+1}{2}}\equiv x\)

有这样一些事情:

1.\((A+B)^p=A^p + B^p\)
通过二项式定理展开为 \(\sum \limits_{j=0}^{p} A^j B^{p-j} \binom{p}{j}\)
其中 \(\binom{p}{j}\) 中的质因子 \(p\) 只在 \(j=0,j=p\) 时不存在。

\[\begin{align*} i^p&=i(i^2)^{\frac{p-1}{2}}\\ &=i(a^2-n)^{\frac{p-1}{2}}\\ &=-i\\ \end{align*}\]

这样的话考虑 \((a+i)^{p+1}\) 这个东西。
可以展开为 \((a+i)^p(a+i)=(a^p+i^p)(a+i)=(a-i)(a+i)=a^2-i^2=n\)
\((a+i)^{\frac{p+1}{2}}\)\(-(a+i)^{\frac{p+1}{2}}\) 是两个解。

可以证明 \((a+i)^{\frac{p+1}{2}}\) 不存在虚部。
假设虚部存在,则有 \((x+yi)^2=n,y\neq 0\)
展开得 \(x^2+y^2(a^2-n)-n=2xy\)
其中左侧不含虚部,故 \(y\neq 0,x=0\)
代入得到 \(y^2i^2=n\),显然无解,与假设不成立。
 
 

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int mod,n,a;
struct node{
	ll r,i;
	node(int r=0,int i=0):r(r),i(i){}
};
inline node operator * (const node &x,const node &y){
	return node((x.r*y.r%mod+x.i*y.i%mod*(1ll*a*a%mod-n+mod))%mod,(x.r*y.i+x.i*y.r)%mod);
}
inline ll qpow(ll x,int k,ll r=1){
	for(;k;k>>=1,x=x*x%mod) if(k&1) r=r*x%mod;
	return r;
}
inline node qpow(node x,int k,node r=node(1,0)){
	for(;k;k>>=1,x=x*x) if(k&1) r=r*x;
	return r;
}
bool check(int x){
	return qpow(x,mod-1>>1)==1;
}
int main(){
	int T; scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&mod);
		if(!n){ puts("0"); continue; }
		if(!check(n)){ puts("Hola!"); continue; }
		for(a=rand()%(mod-1)+1;check((1ll*a*a-n+mod)%mod);a=rand()%(mod-1)+1);
		int x=qpow(node(a,1),mod+1>>1).r,y=mod-x; if(y<x) swap(x,y);
		printf("%d %d\n",x,y);
	}
	return 0;
}
posted @ 2020-07-22 06:16  skyh  阅读(392)  评论(0编辑  收藏  举报