二次剩余 学习笔记

二次剩余 学习笔记

学习资料

OI-wiki, rqy’s blog

约定

以下 p p p 均代指 奇素数 F p \mathbb F_p Fp   m o d   p \bmod p modp 的域。

二次剩余

定义

∃ y ∈ F p ∧ y ≢ 0 ( m o d p ) \exist y\in \mathbb F_p\wedge y\not\equiv 0\pmod p yFpy0(modp) 使得 x ≡ y 2 ( m o d p ) x\equiv y^2\pmod p xy2(modp),则 x x x   m o d   p \bmod p modp 意义下的二次剩余;不存在这样的 y y y,则 x x x 称为非二次剩余。

性质

一、在 1 , 2 , ⋯   , p − 1 1,2,\cdots,p-1 1,2,,p1 中恰有 p − 1 2 \dfrac{p-1}2 2p1 个二次剩余, p − 1 2 \dfrac{p-1}2 2p1 个非二次剩余。

g g g F p \mathbb F_p Fp 的原根,则二次剩余恰为 1 , g 2 , g 4 , ⋯   , g p − 3 1,g^2,g^4,\cdots,g^{p-3} 1,g2,g4,,gp3

二、 x y xy xy 是二次剩余当且仅当 x , y x,y x,y 均是二次剩余或均不是二次剩余。

三、勒让德符号
( a p ) = { 0 a ≡ 0 ( m o d p ) 1 a 是 二 次 剩 余 − 1 a 不 是 二 次 剩 余 \left(\dfrac a p\right)= \left\{\begin{matrix} 0 & a\equiv 0\pmod p\\ 1 & a 是二次剩余\\ -1 & a不是二次剩余 \end{matrix}\right. (pa)=011a0(modp)aa
( a p ) ≡ a ( p − 1 ) / 2 \left(\dfrac a p\right)\equiv a^{(p-1)/2} (pa)a(p1)/2. 这就是二次剩余的判断方法。

证:

a = g u a=g^u a=gu,则 a ( p − 1 ) / 2 = g u ( p − 1 ) / 2 a^{(p-1)/2}=g^{u(p-1)/2} a(p1)/2=gu(p1)/2

u u u 是奇数(即 a a a 为非二次剩余)时, g u ( p − 1 ) / 2 ≡ g ( p − 1 ) / 2 ≡ − 1 g^{u(p-1)/2}\equiv g^{(p-1)/2}\equiv -1 gu(p1)/2g(p1)/21.

u u u 是偶数(即 a a a 为非二次剩余)时, g u ( p − 1 ) / 2 ≡ g 0 ≡ 1 g^{u(p-1)/2}\equiv g^0\equiv 1 gu(p1)/2g01.

Q.E.D.

根据性质二,有
( a b p ) ≡ ( a p ) ( b p ) \left(\dfrac {ab}p\right)\equiv\left(\dfrac ap\right)\left(\dfrac bp\right) (pab)(pa)(pb)

求二次剩余:Cipolla 算法

如何快速求一个 x x x,使 x 2 ≡ n ( m o d p ) x^2\equiv n\pmod p x2n(modp) n n n   m o d   p \bmod p modp 的二次剩余)?

首先我们先找到一个 a a a,使得 a 2 − n a^2-n a2n非二次剩余。可以证明这样的 a a a p − 1 2 \dfrac{p-1}2 2p1 个,直接随机判断即可。

然后我们建立“复数域”。定义 i 2 ≡ a 2 − n i^2\equiv a^2-n i2a2n

x 2 ≡ n ( m o d p ) x^2\equiv n\pmod p x2n(modp) 的解为 ( a + i ) ( p + 1 ) / 2 (a+i)^{(p+1)/2} (a+i)(p+1)/2.

Cipolla算法的证明

首先有一些定理:

定理1: ( a + b ) p ≡ a p + b p ( m o d p ) (a+b)^p\equiv a^p+b^p\pmod p (a+b)pap+bp(modp)

二项式定理展开即可。

定理2: i p ≡ i − 1 i^p\equiv i^{-1} ipi1

证:
i p ≡ i p − 1 ⋅ i ≡ ( i 2 ) ( p − 1 ) / 2 ⋅ i ≡ ( a 2 − n ) ( p − 1 ) / 2 ⋅ i ≡ − i Q . E . D . i^p\equiv i^{p-1}\cdot i\\ \equiv (i^2)^{(p-1)/2}\cdot i\\ \equiv (a^2-n)^{(p-1)/2}\cdot i \equiv -i\\ Q.E.D. ipip1i(i2)(p1)/2i(a2n)(p1)/2iiQ.E.D.
有了这两个定理,那么我们可以验证:
x ≡ ( a + i ) ( p + 1 ) / 2 ≡ ( ( a + i ) p ( a + i ) ) 1 / 2 ≡ ( ( a p + i p ) ( a + i ) ) 1 / 2 ≡ ( ( a − i ) ( a + i ) ) 1 / 2 ≡ ( a 2 − i 2 ) 1 / 2 ≡ n 1 / 2 x\equiv (a+i)^{(p+1)/2}\\ \equiv ((a+i)^p(a+i))^{1/2}\\ \equiv ((a^p+i^p)(a+i))^{1/2}\\ \equiv ((a-i)(a+i))^{1/2}\\ \equiv (a^2-i^2)^{1/2} \equiv n^{1/2} x(a+i)(p+1)/2((a+i)p(a+i))1/2((ap+ip)(a+i))1/2((ai)(a+i))1/2(a2i2)1/2n1/2
x ≡ ( a + i ) ( p + 1 ) / 2 ≡ n 1 / 2 x\equiv (a+i)^{(p+1)/2}\equiv n^{1/2} x(a+i)(p+1)/2n1/2

接下来还要说明 x ∈ F p x\in \mathbb F_p xFp。由于域中的 k k k 次方程至多有 k k k 个解,而 n n n 为二次剩余,所以 x ∈ F p x\in \mathbb F_p xFp。当然还有一解为 − x -x x

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
typedef long long ll;
char In[1 << 20], *ss = In, *tt = In;
#define getchar() (ss == tt && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) ? EOF : *ss++)
ll read() {
	ll x = 0, f = 1; char ch = getchar();
	for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + int(ch - '0');
	return x * f;
}
ll n;
ll P, a, I2;
struct F2 {ll x, y;};
F2 operator * (const F2& A, const F2& B) {return (F2){A.x * B.x % P + I2 * (A.y * B.y % P) % P, (A.x * B.y + A.y * B.x) % P};}
ll qpow(ll a, int n) {ll ret = 1; for(; n; n >>= 1, a = a * a % P) if(n & 1) ret = ret * a % P; return ret;}
F2 qpow(F2 a, int n) {F2 ret = (F2){1, 0}; for(; n; n >>= 1, a = a * a) if(n & 1) ret = ret * a; return ret;}
ll judge(ll a) {return qpow(a, (P-1) / 2);}
void work() {
	n = read(); P = read();
	ll k = judge(n);
	if(k == 0) {
		printf("0\n");
		return ;
	} else if(k == P-1) {
		printf("Hola!\n");
		return ;
	}
	while(1) {
		a = rand() % P;
		I2 = (a * a % P + P - n) % P;
		if(judge(I2) == P-1) break;
	}
	ll ans1 = qpow((F2){a, 1}, (P+1) / 2).x % P;
	ll ans2 = P-ans1;
	if(ans1 > ans2) swap(ans1, ans2);
	printf("%lld %lld\n", ans1, ans2);
}
	

int main() {
	int T = read();
	while(T--) work();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

日居月诸Rijuyuezhu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值