二次剩余(Cipolla)

question

求解

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

使用(\(Cipolla\))算法,仅可求解 \(p\) 是奇素数的情况

解的个数

我们称一个数为二次剩余当且仅当存在 \(x^2 \equiv n\ (mod\ p)\) 否则为非二次剩余

考虑二次剩余 \(n\) 有多少个解

\(n\) 的解中任取出 2 个 \(x_0, x_1, x_0 \ne x_1\)

\[x_0^2 \equiv x_1^2 \]

移项

\[x_0^2 - x_1^2 \equiv 0 \]

\[(x_0 + x_1) (x_0 - x_1) \equiv 0 \]

已知 \(x_0 \ne x_1\)\(x_0 + x_1 \equiv 0\)

由此可知 \(x_0, x_1\) 互为相反数,且每一对相反数都对应不同的二次剩余

而且由于 \(p\) 是奇素数 \(x_0 \ne x_1\)

那么我们知道了,奇素数 \(p\)\(\frac {p - 1} {2}\) 个二次剩余

欧拉准则

我们知道了解的数量,如何判断一个数 \(n\) 是不是二次剩余呢?

\(n \ne 0\)

  • \(n\) 是二次剩余 \(\iff n^{\frac{p-1}{2}} \equiv 1\)

引理1

\[n ^ {\frac{p - 1} 2} \equiv \pm 1\ (mod\ p) \]

  • 证明

由欧拉定理得知

\[n ^ {p - 1} \equiv 1 \]

\[n ^ {2 \frac {p - 1} 2} \equiv 1 \]

\[n ^ {\frac {p - 1} 2} \equiv \sqrt 1 \]

\(n ^ {\frac {p - 1} 2}\) 是 1 开方的结果,所以只能是 \(\pm 1\)

证明

\(g\)\(p\) 的原根,\(n \equiv g^k\)

\(n ^ {\frac {p - 1} 2} \equiv 1\)\(g ^ {k \frac {p - 1} 2} \equiv 1\)

因为 \(g\) 是原根 \((p - 1) | ( k \frac{p - 1} 2)\)

那么 \(k\) 一定是偶数

\(g^{\frac k 2}\) 就是 \(n\) 的一个解

由此我们得出如果 \(n ^ {\frac{p-1}{2}} \equiv 1\)\(n\) 是二次剩余

如果 \(n\) 是二次剩余 \(n ^ {\frac{p - 1} 2} \equiv (x^2)^{\frac{p - 1} 2} \equiv x^{p - 1} \equiv 1\)

\(Cipolla\) 算法

对于 \(x^2 \equiv n\) 找到一个 \(a\) 使得 \(a^2 - n\)非二次剩余

这一步期望复杂度 \(O(2)\) 因为非二次剩余个数接近 \(\frac n 2\)

定义 \(i^2 \equiv a^2 - n, i\) 是类似复数一样的东西

所有数都可以表示成 \(A + Bi\)

\((a + i)^{\frac{p + 1} 2}\) 即为一个解

引理 1

\[i^p \equiv -i\ (mod\ p) \]

  • 证明

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

因为 \(a^2 - n\) 是非二次剩余,\((a^2 - n)^ {\frac{p - 1} 2} \equiv -1\)

引理 2

\[(A + B)^p \equiv A^p + B^p\ (mod\ p) \]

\[(A + B)^p = \sum_{i = 0} ^ p \binom p i A^iB^{p - i} \]

\[\binom p i = \frac{p!}{i!(p - i)!} \]

因为 \(p\) 是素数,所有包含 \(p\) 的阶乘都被模成了 \(0\) 只剩下了 \(\binom p 0 B^p + \binom p p A^p\)

证明

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

\((a + i)^{\frac{p + 1} 2}\) 就是答案

那么 \((a + i)^{\frac{p + 1} 2}\) 的虚部是否为 0 呢

假设存在 \((A + Bi) ^ 2 \equiv n, B \ne 0\)

\[A^2 + B^2 i^2 - n \equiv 2ABi \]

左边虚部为 0 说明右边也为 0

\(AB \equiv 0\),因为 \(B \ne 0\)\(A \equiv 0\),那么

\[(A + Bi)^2 \equiv B^2 i^2 \equiv n \]

\[i^2 \equiv n B^{-2} \]

因为 \(n\) 是二次剩余,设 \(x^2 \equiv n\)

\[i ^ 2 \equiv (xB^{-1}) ^ 2 \]

\(i ^ 2\) 显然是二次剩余,与前提矛盾

证毕

板子

#include <bits/stdc++.h>
using namespace std;
#define I inline
#define int long long
int imuli, mod, n;
struct cpx{
	int a, b;
	cpx(int a, int b): a(a), b(b) {}
	I cpx operator * (const cpx &rhs) const {
		return cpx((a * rhs.a % mod + b * rhs.b % mod * imuli % mod) % mod, (a * rhs.b % mod + b * rhs.a % mod) % mod);
	}
};
I cpx ksm(cpx a, int b){
	cpx ans(cpx(1, 0));
	while(b){ if(b & 1) ans = ans * a; b >>= 1; a = a * a; }
	return ans;
}
I int ksm(int a, int b){
	int ans = 1;
	while(b){ if(b & 1) ans = ans * a % mod; b >>= 1; a = a * a % mod; }
	return ans;
}
I bool check(int n){
	return ksm(n, (mod - 1) / 2) == 1;
}
I void Main(){
	cin >> n >> mod;
	n %= mod;
	if(!n) return cout << 0 << '\n', void();
	if(n == 2) return cout << "1" << '\n', void();
	if(!check(n)) return cout << "Hola!" <<'\n', void();
	int a;
	do{
		a = (1ll * rand() + 1ll * rand() * rand()) % mod;
	}while(check((a * a + mod - n) % mod));
	imuli = (a * a % mod + mod - n) % mod;
	int x0 = ksm(cpx(a, 1), (mod + 1) / 2).a, x1 = mod - x0;
	if(x0 > x1) swap(x0, x1);
	cout << x0 << " " << x1 << '\n';
}
signed main(){
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int T; cin >> T;
	while(T--) Main();
	return 0;
}
  • \(tps\): cpx 里面的 b 可以 % mod 是因为最终虚部为 0 剩下的 b 在做乘法的时候需要 % mod
posted @ 2020-06-07 11:25  __int256  阅读(413)  评论(1编辑  收藏  举报