二次剩余(Cipolla)

题意

给定一个正整数 n n n,解方程

x 2 ≡ n ( m o d p ) x^2 \equiv n \pmod{p} x2n(modp)

这里只考虑 p p p 为奇素数的情况。


解的个数

假设对于 n n n 有多个解,其中两个为 x 1 x_1 x1 x 2 x_2 x2

那么有

x 1 2 − x 2 2 ≡ 0 ( m o d p ) x_1^2 - x_2^2 \equiv 0\pmod{p} x12x220(modp)

( x 1 − x 2 ) ( x 1 + x 2 ) ≡ 0 ( m o d p ) (x_1 - x_2)(x_1 + x_2) \equiv 0\pmod{p} (x1x2)(x1+x2)0(modp)

因为 x 1 ≠ x 2 x_1 \ne x_2 x1=x2,那么 x 1 x_1 x1 x 2 x_2 x2 就一定是相反数,所以对于一个 n n n 要么有两个解,要么无解。

如果对于 n n n 有两个解,则称它为二次剩余,否则为二次非剩余。

顺带一提,因为一对相反数只能构成一个二次剩余,所以二次剩余的个数为 p − 1 2 \frac{p-1}{2} 2p1 个。


Legendre 符号

( a p ) = { 0 , p ∣ a , 1 , ( p ∤ a ) ∧ ( ( ∃ x ∈ Z ) , x 2 ≡ a ( m o d p ) ) , − 1 , o t h e r w i s e . \left(\frac{a}{p}\right)=\left\{\begin{array}{l} 0, & p\mid a, \\ 1, & (p\nmid a) \wedge ((\exists x \in Z), x^2\equiv a\pmod{p}), \\ -1, & otherwise.\\ \end{array}\right. (pa)= 0,1,1,pa,(pa)((xZ),x2a(modp)),otherwise.


欧拉准则

对于奇素数 p p p 和正整数 a a a,有

a p − 1 2 ≡ ( a p ) ( m o d p ) a^{\frac{p-1}{2}} \equiv \left(\frac{a}{p}\right) \pmod{p} a2p1(pa)(modp)

接下来我们证明一下这个结论,设 g g g p p p 的一个原根,且有 g q ≡ a ( m o d p ) g^q \equiv a \pmod{p} gqa(modp)

引理1

a a a 为二次剩余,当且仅当 q q q 为偶数。

先证明充分性

q q q 为偶数,那么就有一个解为 g q 2 g^{\frac{q}{2}} g2q,即 a a a 为二次剩余。

再证明必要性

x = g y x = g^{y} x=gy x 2 ≡ a ( m o d p ) x^2\equiv a\pmod{p} x2a(modp) 的一个解,那么就有

g 2 y ≡ g q ( m o d p ) g^{2y} \equiv g^q \pmod{p} g2ygq(modp)

2 y ≡ q ( m o d φ ( p ) ) 2y \equiv q\pmod{\varphi(p)} 2yq(modφ(p))

因为 2 y 2y 2y φ ( p ) \varphi(p) φ(p) 都是偶数,所以 q q q 也一定是偶数。

证明

那么有

a p − 1 2 ≡ ( g p − 1 2 ) q ≡ ( − 1 ) q ( m o d p ) a^{\frac{p-1}{2}} \equiv (g^{\frac{p-1}{2}})^q \equiv (-1)^q \pmod{p} a2p1(g2p1)q(1)q(modp)

根据引理1得出的结论,若 a a a 为二次剩余,则 q q q 为偶数,否则为奇数,所以 ( − 1 ) q ≡ ( a p ) ( m o d p ) (-1)^q \equiv \left(\frac{a}{p}\right) \pmod{p} (1)q(pa)(modp)

证毕。


Cipolla 算法

我们先找到一个 a a a,使得 a 2 − n a^2 - n a2n 是二次非剩余,由于二次非剩余出现概率为 1 2 \frac{1}{2} 21,所以用随机数很容易得到一个合适的 a a a

根据欧拉准则,有 ( a 2 − n ) p − 1 2 ≡ − 1 ( m o d p ) (a^2-n)^{\frac{p-1}{2}} \equiv -1 \pmod{p} (a2n)2p11(modp)

我们重新定义一个虚数概念,将虚数单位 i i i 定义为 i 2 ≡ a 2 − n ( m o d p ) i^2 \equiv a^2 - n\pmod{p} i2a2n(modp),将所有虚数表示为 A + B i A + Bi A+Bi 的形式( A , B ∈ R A,B\in R A,BR),并且认为模 p p p 意义下的虚数为对于 A , B A,B A,B 分别取模。

引理1

i p ≡ − i ( m o d p ) i^p\equiv -i\pmod{p} ipi(modp)
证明: i p ≡ i ( i 2 ) p − 1 2 ≡ i ( a 2 − n ) p − 1 2 ≡ − i ( m o d p ) i^p \equiv i (i^2)^{\frac{p-1}{2}} \equiv i (a^2 - n)^{\frac{p-1}{2}} \equiv -i \pmod{p} ipi(i2)2p1i(a2n)2p1i(modp)

引理2

( 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)
证明:运用二项式定理,只有 C p 0 C_p^0 Cp0 C p p C_p^p Cpp 不是 p p p 的倍数,所以等于 A p + B p A^p + B^p Ap+Bp

有了以上引理,进行计算 ( a + i ) p + 1 ≡ ( a + i ) p ( a + i ) ≡ ( a p + i p ) ( a + i ) ≡ ( a − i ) ( a + i ) ≡ a 2 − i 2 ≡ n ( m o d p ) (a+i)^{p+1} \equiv (a+i)^p (a+i) \equiv (a^p + i^p)(a+i) \equiv (a-i)(a+i) \equiv a^2 - i^2 \equiv n \pmod{p} (a+i)p+1(a+i)p(a+i)(ap+ip)(a+i)(ai)(a+i)a2i2n(modp),于是我们得到一个解 ( a + i ) p + 1 2 (a+i)^{\frac{p + 1}{2}} (a+i)2p+1

这时我们有一个疑问,这个数一定是实数吗?

运用反证法,设存在一个虚数解 A + B i A + Bi A+Bi 满足方程 ( A + B i ) 2 ≡ n ( m o d p ) ( B ≠ 0 ) (A+Bi)^2 \equiv n \pmod{p}(B\ne 0) (A+Bi)2n(modp)B=0

那么有 A 2 + B 2 i 2 + 2 A B i ≡ n ( m o d p ) A^2 + B^2i^2 + 2ABi \equiv n \pmod{p} A2+B2i2+2ABin(modp)

A 2 + B 2 ( a 2 − n ) − n ≡ 2 A B i ( m o d p ) A^2 + B^2(a^2 - n) - n \equiv 2ABi \pmod{p} A2+B2(a2n)n2ABi(modp)

由于方程左边不是虚数,所以右边也一定不是虚数,即 A = 0 A=0 A=0,于是 ( B i ) 2 ≡ n ( m o d p ) (Bi)^2 \equiv n\pmod{p} (Bi)2n(modp)

得到 i 2 ≡ n B − 2 ( m o d p ) i^2 \equiv n B^{-2}\pmod{p} i2nB2(modp) 由于 n n n B − 2 B^{-2} B2 均为二次剩余,所以右边一定为二次剩余,而左边不是,矛盾,假设不成立。

所以得出的解一定是实数。


代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;

ll I_mul_I, mod;

struct Complex {
	ll a, b;
	Complex operator* (Complex y) {
		return {(a * y.a % mod + b * y.b % mod * I_mul_I % mod) % mod, (a * y.b % mod + b * y.a % mod) % mod};
	}
};

ll qpow(ll x, ll y) {
	ll res = 1;
	while (y) {
		if (y & 1) res = res * x % mod;
		x = x * x % mod;
		y >>= 1;
	}
	return res;
}

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

bool legendre(ll x) {
	return qpow(x, (mod - 1) >> 1) == 1;
}

ll cipolla(ll n, ll p) {
	n %= p, mod = p;
	if (!n) return 0;
	if (!legendre(n)) return -1;
	ll a = rand() % mod;
	while (legendre((a * a + mod - n) % mod)) a = rand() % mod;
	I_mul_I = (a * a + mod - n) % mod;
	return qpow(Complex({a, 1}), (mod + 1) >> 1).a;
}

int main() {
	srand(time(0));
	int T;
	scanf("%d", &T);
	while (T -- ) {
		ll x, p;
		scanf("%lld%lld", &x, &p);
		ll ans = cipolla(x, p);
		if (ans == -1) puts("Hola!");
		else if (ans == 0) puts("0");
		else {
			if (ans > p - ans) ans = p - ans;
			printf("%lld %lld\n", ans, p - ans);
		}
	}
	return 0;
}
  • 45
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值