二次剩余学习笔记
给定奇素数 \(p\) 和 正整数\(n\) ,求所有 \(x\) 满足 \(x^2 \equiv n \pmod p\) 。
如果有多个解,假设有两个不同解 \(x_1, x_2\) ,那么有 \(x_1^2 \equiv x_2^2 \equiv n\) ,即 \(x_1^2-x_2^2 \equiv (x_1-x_2)(x_1+x_2) \equiv 0 \pmod p\) 。
因为 \(x_1 \neq x_2\) ,所以 \(x_1 \equiv -x_2\) 。因此如果有两个解不同则它们互为相反数。
又因为 \(p\) 为奇素数,所以不存在 \(x \equiv -x\) 的情况,所以如果有解就一定有两个解。
现在我们定义一个数 \(n\) 是二次剩余,当且仅当方程 \(x^2 \equiv n \pmod p\) 有解。
根据欧拉准则, \(n\) 是二次剩余当且仅当 \(n^{\frac{p-1}{2}} \equiv 1\) 。
证明:
如果 \(n\) 是二次剩余,假设 \(x^2 \equiv n \pmod p\) 且 \(n^{\frac{p-1}{2}} \equiv 1 \pmod p\) ,则 \(x^{p-1} \equiv 1 \pmod p\) ,通过费马小定理可知这是成立的。
如果 \(n^{\frac{p-1}{2}} \equiv 1 \pmod p\) ,设 \(g^k \equiv n \pmod p\) ,其中 \(g\) 是 \(p\) 的一个原根,那么有 \(g^{k\frac{p-1}{2}} \equiv 1 \pmod p\) 。因为 \(g\) 是原根,那么一定有 \(p-1 | k\frac{p-1}{2}\) ,也就是说 \(2|k\) 。那么显然有 \(x \equiv g^{\frac{k}{2}} \pmod p\) ,即 \(n\) 是二次剩余。
证毕。
所以一个数 \(n\) 如果是二次剩余,假设 \(n \equiv g^k \pmod p\) ,当且仅当 \(2|k\) 。而因为 \(g\) 是原根,这样的 \(k\) 一共有 \(\frac{p-1}{2}\) 个,也就是说模 \(p\) 意义下的二次剩余个数一共有 \(\frac{p-1}{2}\) 个。这就告诉我们一件事:如果随机取一个 \([0,p-1]\) 中的数,期望取两个数就能得到一个二次剩余/非二次剩余的数。而 \(n^{p-1} \equiv 1 \pmod 1\) ,我们知道 \(1\) 开根要么是 \(1\) 要么是 \(-1\) ,所以如果 \(n\) 不是二次剩余则 \(n^{\frac{p-1}{2}} \equiv -1 \pmod p\) 。
求解二次剩余的解,对于 \(p\) 是奇素数的情况,通常使用 \(\rm Cipolla\) 算法 \(\mathcal{O}(\log n)\) 求解。
首先我们找一个 \(a\) 满足 \(a^2-n\) 不是二次剩余。根据刚才的证明,我们期望两次能找出这个 \(a\) 。
接下来定义 \(i^2 \equiv a^2-n \pmod p\) 。但前面说了 \(a^2-n\) 不是二次剩余,怎么办呢?
这里就是 \(\rm Cipolla\) 的核心思想,类似于实数到复数的扩域过程,定义 \(A+Bi \equiv a^2-n\) 。
引理\(1\) : \(i^p \equiv -i \pmod p\) 。
证明: \(i^p \equiv i(i^2)^{\frac{p-1}{2}} \equiv i(a^2-n)^{\frac{p-1}{2}} \equiv -i \pmod p\) 。
引理\(2\) : \((A+B)^p \equiv A^p+B^p\) 。
这个很显然,用二项式定理展开后为: \(\sum_{i=0}^p {p \choose i}A^iB^{p-i}\) 。
当 \(0<i<p\) 时,有 \({p \choose i} \equiv 0 \pmod p\) 。
否则 \({p \choose 0} \equiv {p \choose p} \equiv 1 \pmod p\) 。
因此 \((A+B)^p \equiv A^p+B^p\) 。
定理 : \((a+i)^{p+1} \equiv n \pmod p\) 。
根据引理 \(2\) 把式子展开得 \((a+i)^{p+1} \equiv a^{p+1}+i^{p+1} \equiv a^2+i^{p+1} \pmod p\) 。根据引理 \(1\) 化掉 \(i^{p+1}\) 得 \(a^2-i^2 \equiv n \pmod p\) 。
因此我们的答案貌似就是 \(x \equiv (a+i)^{\frac{p+1}{2}} \pmod p\) ,唯一的问题就是 \(x\) 是否虚部为 \(0\) 。
假设存在 \((A+Bi)^2 \equiv n\) 且 \(B \neq 0\) ,则 \(A^2+2ABi+B^2i^2 \equiv A^2+2ABi+B^2(a^2-n) \equiv n\) 。
因为右边的虚部为 \(0\) ,所以左边的虚部也为 \(0\) ,即 \(AB \equiv 0\) 。因为 \(B \neq 0\) ,所以 \(A \equiv 0\) ,即 \((0+Bi)^2 \equiv B^2(a^2-n) \equiv n \pmod p\) ,即 \(a^2-n \equiv nB^{-2}\) 。
因为 \(n\) 是二次剩余,而 \(B^{-2}\) 也肯定是二次剩余,而 \(a^2-n\) 不是二次剩余,所以矛盾,因此 \(B = 0\) 。
#include<bits/stdc++.h>
#define rg register
#define il inline
#define cn const
using namespace std;
int T, n, mod, iimg;
struct com{int x, y;};
il com operator * (cn com &a, cn com &b){return (com){(int)((1ll*a.x*b.x+1ll*a.y*b.y%mod*iimg)%mod), (int)((1ll*a.x*b.y+1ll*a.y*b.x)%mod)};}
il int fpow(int a, int b, int ans = 1){
for(; b; b >>= 1, a = 1ll*a*a%mod)if(b&1)ans = 1ll*ans*a%mod;
return ans;
}
il int fpow(com a, int b, com ans = (com){1, 0}){
for(; b; b >>= 1, a = a*a)if(b&1)ans = ans*a;
return ans.x;
}
int main(){
cin >> T, srand(time(0));
while(T--){
cin >> n >> mod;
if(mod == 2){printf("%d\n", n%mod); continue;}
if(n == 0){puts("0"); continue;}
if(fpow(n, mod-1>>1) == mod-1){puts("Hola!"); continue;}
rg int a, ans1, ans2;
while(1){
a = 1ll*rand()*rand()%mod;
if(fpow((1ll*a*a-n+mod)%mod, mod-1>>1) == 1)continue;
iimg = (1ll*a*a-n+mod)%mod, ans1 = fpow((com){a, 1}, mod+1>>1), ans2 = mod-ans1;
break;
}
if(ans1 > ans2)ans1 ^= ans2 ^= ans1 ^= ans2;
printf("%d %d\n", ans1, ans2);
}
return 0;
}