二次剩余小结

二次剩余

定义

对于模数(n)和整数(a),若存在整数(x),满足

[x^2equiv a(mod n) ]

则称(x)是模(n)意义下的二次剩余,否则是非二次剩余

注:这里讨论的(x)满足(xin[1,n))

判定

欧拉判别法:对于奇素数(p)(a)是模(p)意义下的二次剩余当且仅当(a^{frac{p-1}{2}}equiv 1(mod p))

类似的,若(a)是模(p)意义下的二次非剩余则有(a^{frac{p-1}{2}}equiv-1(mod p))

证明

先证明在(a mid p)时,(a^{frac{p-1}{2}}equiv 1或-1(mod p))

由费马小定理知(a^{p-1}equiv 1(mod p))

移项,利用平方差公式得((a^{frac{p-1}{2}}+1)(a^{frac{a-1}{2}}-1)equiv 0(mod p))

再由(p)是奇素数知上两式中必有且仅有一个同余于0

再证明若(a)是二次剩余的充要条件为(a^{frac{p-1}{2}}equiv 1(mod p))

先证必要性,若(a)是模(p)意义下的二次剩余,那么必有整数(x_0^2equiv a(mod p)),且(p mid x_0)

同时做(frac{p-1}{2})次方,有(a^{frac{p-1}{2}}equiv x_0^{p-1}equiv 1(mod p))

再证充分性,设有(a^{frac{p-1}{2}}equiv 1(mod p))

对于([1,p))中的整数,考虑如下的同余方程

[xyequiv a(mod p) ]

注意到,对于任意的整数(xin[1,p)),一定有且仅有一个(yin[1,p))满足上式

假设(a)不是二次剩余,那么对(forall x),均有(y eq x)

也就是说对于([1,p))中的(p-1)个整数,我们可以将它们分成(frac{p-1}{2})组,使得每一个数均正好属于一组

将这(p-1)个数乘起来,有

[(p-1)!~equiv a^{frac{p-1}{2}}(mod p) ]

由威尔逊定理,有((p-1)!equiv -1(mod p)),也就是(a^{frac{p-1}{2}}equiv -1(mod p)),与题设矛盾

故假设错误,所以一定有(a)是模(p)意义下的二次剩余

勒让德(Legendre)符号

方便描述,我们定义勒让德(Legendre)符号(egin{pmatrix}frac{n}{p}end{pmatrix})

[egin{pmatrix}frac{n}{p}end{pmatrix}= egin{cases} 0 & a|p\ -1 & a不是模p意义下的二次剩余\ 1 & a是模p意义下的二次剩余 end{cases} ]

具体求值的话可以利用上面的欧拉判别法(仅当(p)是奇素数时)

求解

先证明一个定理:

在模(p)意义下的一个简化剩余系中,有(frac{p-1}{2})个数具有二次剩余,且一个模(p)意义下的二次剩余(a),有两个不同的(x)满足(x^2equiv a(mod p))

证明

取模(p)意义下的一个简化剩余系如下

[-frac{p-1}{2},-frac{p-1}{2}+1,cdots,-1,1,2,cdots,frac{p-1}{2} ]

(a)是模(p)意义下的二次剩余,仅当

[aequiv(-frac{p-1}{2})^2或(-frac{p-1}{2}+1)^2cdots或(frac{p-1}{2})^2(mod p) ]

又由((-x)^2=x^2)知,若(a)是模(p)意义下的二次剩余,仅当

[aequiv 1^2或2^2或cdots或(frac{p-1}{2})^2(mod p) ]

且我们知道在(1leq i<jleq frac{p-1}{2})时,(i^2)(j^2)在模(p)意义下不相等,所以上面给出的(frac{p-1}{2})个数的平方恰好对应了在模(p)的意义下有二次剩余的(frac{p-1}{2})个不同的数,所以在模(p)的意义下(p)的简化剩余系中有(frac{p-1}{2})个数有二次剩余

根据上面的证明,对于一个二次剩余(a),那么一定存在(xin[1,frac{p-1}{2}]),使得(x^2equiv a(mod p))

那么在一开始提到的简化剩余系中,一定还有一个(-x)使得((-x)^2equiv a(mod p))

于是就有两个不同的(x)使得(x^2equiv a(mod p))

那么这和求解有什么关系呢?

首先判掉不是二次剩余的情况

接下来有2个(x)满足(x^2equiv a(mod p)),我们只需要求出一个,由上面的证明知另一个和它的和为(p)

(接下来介绍高端操作)

假设我们要求(x^2equiv n(mod p)),其中(p)是一个奇素数

我们先随便找一个数(a),满足(egin{pmatrix}frac{a^2-n}{p} end{pmatrix}=-1)

(omega=sqrt{a^2-n}),那么(x=(a+omega)^frac{p+1}{2})

正确性呢?

证明

(x^2=(a+omega)^{p+1}=(a+omega)^p(a+omega)=(a+omega)sum_{i=0}^pdbinom{p}{i}a^iomega^{p-i})

注意到(1leq i<p)时,(p|dbinom{p}{i})

于是(x^2equiv(a^p+omega^p)(a+w) (mod p))

我们由费马小定理知(a^{p-1}equiv 1(mod p)),所以(a^pequiv a(mod p))

那这个(omega^p)是什么,他甚至可能不是整数

我们由上面的操作过程知(omega^{p-1}=(omega^2)^{frac{p-1}{2}}equiv(a^2-n)^{frac{p-1}{2}}equiv -1(mod p))

所以(omega^pequiv -omega(mod p))

于是(x^2equiv(a-omega)(a+omega)equiv a^2-(a^2-n)equiv n(mod p))

证毕

然后你就会发现这个做法的时间复杂度和找(a)所花的时间有关

然而你由上面的证明过程知你有(frac{1}{2})的几率找到一个合法的(a)

然后就做完了?这个(omega)可以是无理数!

仿照复数(a+bi)的形式,我们将所有数写成(a+bomega),这里的话重新写一个乘法就可以了

模板题:http://acm.timus.ru/problem.aspx?space=1&num=1132

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define fir first
#define sec second
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define maxd 1000000007
#define eps 1e-6
typedef long long ll;
const int N=100000;
const double pi=acos(-1.0);
ll w,p,n;
struct Complex{
	ll x,y;
	Complex(ll _x=0,ll _y=0) {x=_x;y=_y;}
};
Complex operator *(Complex a,Complex b) 
{
	return Complex((a.x*b.x%p+a.y*b.y%p*w%p)%p,(a.x*b.y+a.y*b.x)%p);
}
ll qpow(ll x,ll y,ll p)
{
	ll ans=1;
	while (y)
	{
		if (y&1) ans=ans*x%p;
		x=x*x%p;
		y>>=1;
	}
	return ans;
}

Complex qpow(Complex a,ll y)
{
	Complex ans=Complex(1,0);
	while (y)
	{
		if (y&1) ans=ans*a;
		a=a*a;
		y>>=1;
	}
	return ans;
}

int read()
{
	int x=0,f=1;char ch=getchar();
	while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
	while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
	return x*f;
}

ll Legendre(ll x)
{
	return qpow(x,(p-1)>>1,p);
}

int main()
{
	srand(19260817);
	int T=read();
	while (T--)
	{
		scanf("%lld%lld",&n,&p);
		if (p==2) puts("1");
		else
		{
			if (Legendre(n)+1==p) puts("No root");
			else
			{
				ll a;
				while (1)
				{
					a=rand()%p;
					w=((a*a-n)%p+p)%p;
					if (Legendre(w)+1==p) break; 
					//cout << Legendre(w) << " " << w << endl;
					//system("pause");
				}
				ll ans1=qpow(Complex(a,1),(p+1)>>1).x;
				ll ans2=p-ans1;
				if (ans1>ans2) swap(ans1,ans2);
				printf("%lld %lld
",ans1,ans2);
			}
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/encodetalker/p/10912415.html