二次剩余
二次剩余常用来求解\(x^2 \equiv n(mod\ p)\),给出\(n,p(p\in \{奇素数\})\)求\(x\)的问题中
即对\(p\)进行\(mod\ p\)意义下的开根
如果说
\(\begin{cases}存在 x\in N^*,x^2\equiv n(mod\ p)& n为二次剩余 \\ 不存在 x\in N^*,x^2\equiv n(mod\ p)&n不为二次剩余\end{cases}\)
举个栗子
在\(mod\ 7\)意义下
\(a\) | \(a^2\) |
---|---|
0 | 0 |
1 | 1 |
2 | 4 |
3 | 2 |
4 | 2 |
5 | 4 |
6 | 1 |
\(\therefore \sqrt 0 = 0\ \ \ \ \ \ \sqrt 1=1,6 \ \ \ \ \ \ \sqrt 2 = 3,4\ \ \ \ \ \ \sqrt 4 = 2,5\)
其他的没有
预先声明
- 为了方便我们先引入勒德让符号:
\((\frac n p) = \begin{cases} 1 & n为二次剩余 & 记作QR\\ 0&n\equiv0(mod\ p) &记作0\\-1&n不为二次剩余&记作NR\end{cases}\)
- 先知道\((n-p)^2\equiv n(mod\ p)\)
\((n-p)^2 = n^2 - 2np+p^2 = n^2+p(p-2n)\equiv n^2(mod\ p)\)
反映在表上即上下对称
- \(n^{p-1}\equiv 1(mod\ p)\ \ \ (p,n)互质\)——费马小定理
\({(n^2)}^{p-1} \equiv 1(mod\ p)\\ (n^{p-1})^2 - 1^2\equiv0(mod\ p)\\(n^{\frac{p-1}2}+1)(n^{\frac{p-1}2}-1)\equiv0(mod\ p)\)
- 欧拉准则
若\(p\)为奇素数,则\(a^{\frac{p-1}2} = (\frac{a}{p})\)
证明:不会,没学原根QaQ~
- 二项式定理
\((a+b)^n = \sum_{i=1}^{n} C_n^i\times a^i\times b^{n-i}\)
又因为:
\(\forall i\in (0,n) 且i \in Z,C_n^i\mod n = 0\)
所以说:
\((a+b)^p \mod p = C_p^0\times a^p + C_p^p\times b^p = a^p + b^p\)
算法流程
首先随机\(a\in Z\),
然后我们使用欧拉准则\(_{声明4}\)验证\((\frac{a^2-n}{p})\)是否等于\(-1\),
注:期望为\(\Theta(2)\),因为\((\frac {i} {p}) = -1\)的数量为\(\frac{p}{2}\)(证明?后面补,逃)
我们令\(i = \sqrt{a^2-n}\),(此处的i类似于复数\(C\),但并不是!)
可以求出答案即为:
\(\begin{cases}x_1 = (a+i)^{\frac{p+1}2} \\ x_2 = -(a+i)^{\frac{p+1}2}\end{cases}\)
证明:
\((a+i)^{p+1}\)
$ = (a+i)(a+i)^p$
\(=(a+i)(a^p+i^p)\)……\(二项式定理_{声明5}\)
\(=(a+i)(a - i)\)……费马小定理\(_{声明3}\)+\((\frac{a^2-n}{p}) = {(i^2)}^{\frac{p-1}{2}} = i^{p-1}=-1\)
\(= a^2 - i^2\)
\(= a^2-(a^2-n) = n\)
最后:如何把\(i\)这个可恶的东西计算进去?
可以像复数计算一样计算\(a+i\),只需要建一个虚数类即可
可以证明最后的最后计算出来的数不包含\(i\) 又不会,QAQ
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read(){
register ll res = 0,flag = 1;
register char c = getchar();
while(!isdigit(c)){
if(c == '-')flag = -1;c = getchar();
}
while(isdigit(c)){
res = res * 10 + c - '0';
c = getchar();
}
return res * flag;
}
ll t,n,p,w;
struct Num{
ll x,y;
Num operator * (const Num &b) const{
Num res;
res.x=((x*b.x%p+y*b.y%p*w%p)%p+p)%p;// x = a.x*b.x + a.y*b.y*w
res.y=((x*b.y%p+y*b.x%p) %p+p)%p;// y = a.x*b.y + a.y*b.x
return res;
}
};
ll qpow_r(ll x,ll k){
ll res = 1,c = x;
while(k){
if(k&1)res = res * c % p;
c = c * c % p;
k >>= 1;
}
return res;
}
ll qpow_i(Num a,ll b,ll p){
Num res = {1,0};
while(b){
if(b&1) res = res * a;
a = a * a;
b >>= 1;
}
return res.x % p;
}
ll cipolla(ll n,ll p){
n %= p;
if(qpow_r(n,(p-1)/2)==p-1) return -1;
ll a;
while(1){
a = rand()%p;
w = (((a*a)%p-n)%p+p)%p;
if(qpow_r(w,(p-1)/2) == p-1)break;
}
Num res = {a,1};
return qpow_i(res,(p+1)/2,p);
}
int main(){
srand(time(0));
t = read();
while(t--){
n = read(); p = read();
if(!n){
printf("0\n");continue;
}
ll ans1 = cipolla(n,p),ans2 = -ans1 + p;
if(ans1 == -1)puts("Hola!");
else{
if(ans1 > ans2)swap(ans1,ans2);
if(ans1 == ans2)printf("%lld\n",ans1);
else printf("%lld %lld\n",ans1,ans2);
}
}
}
本文来自博客园,作者:ricky_lin,转载请注明原文链接:https://www.cnblogs.com/rickylin/p/17055754.html