概念
偶质数:既是质数,又是偶数的数称为偶质数。(只有2)
奇质数:既是质数,又是奇数的数称为奇质数。(除了2以外的质数)
二次剩余定理
二次剩余定理能够解方程:
x
2
=
n
(
m
o
d
p
)
x^2 = n (mod\ p)
x2=n(mod p) 其中p是一个奇质数。
二次剩余定理告诉我们,这个方程的解是 x = ( a + w ) p + 1 x= (a + \sqrt[]w )^{p + 1} x=(a+w)p+1
核心
判断是否有解核心有两点:一是利用费马小定理,二是构造平方差公式(脑洞)
证明过程
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL w;
struct T{
LL p, d;
};
LL quick_mod(LL a, LL b, LL m){//快速幂
LL ans = 1;
while(b){
if(b & 1)
ans = ans * a % m;
a = a * a % m;
b >>= 1;
}
return ans;
}
T multi_er(T a, T b, LL m){//二次域乘法
T ans;
ans.p = (a.p * b.p % m + a.d * b.d % m * w % m) % m;
ans.d = (a.p * b.d % m + a.d * b.p % m) % m;
return ans;
}
T power(T a, LL b, LL m){//二次域上快速幂
T ans;
ans.p = 1;
ans.d = 0;
while(b){
if(b & 1){
ans = multi_er(ans, a, m);
b--;
}
b >>= 1;
a = multi_er(a, a, m);
}
return ans;
}
LL Legendre(LL a, LL p){//求勒让德符号
return quick_mod(a, (p-1)>>1, p);
}
LL mod(LL a, LL m){
a %= m;
if(a < 0) a += m;
return a;
}
LL Solve(LL n,LL p){
if(p == 2) return 1;
if (Legendre(n, p) + 1 == p)
return -1;
LL a = -1, t;
while(true){
a = rand() % p;
t = a * a - n;
w = mod(t, p);
if(Legendre(w, p) + 1 == p) break;
}
T tmp;
tmp.p = a;
tmp.d = 1;
T ans = power(tmp, (p + 1)>>1, p);
return ans.p;
}
int main(){
int t;
scanf("%d", &t);
while(t--){
LL n, p;//n是余数,p是mod
scanf("%lld %lld", &n, &p);
n %= p;
LL a = Solve(n, p);
if(a == -1)//x无解的情况
{
puts("No root");
continue;
}
//有解的情况下
LL b = p - a;
if(a > b)
swap(a, b);
if(a == b)//如果两个解相同,输出一个即可
printf("%lld\n", a);
else//如果两个解不同,分别输出(从小到大)
printf("%lld %lld\n", a, b);
}
return 0;
}
参考来源
acmdreamer的博客,跟着推导完后还是很迷糊。这篇博文后面还讲了模数是Pn 的方程的求解。
https://blog.csdn.net/acdreamers/article/details/10182281
博客,这篇博客讲的很好很详细。
https://blog.csdn.net/a_crazy_czy/article/details/51959546
博客
https://blog.csdn.net/qq_33229466/article/details/79125057