二次剩余(模板)
二次剩余
存在 \(x^2\ \%\ p = n\), 如果存在这样的\(x\)那么,认为\(( \dfrac{n}{p})\) 有解。
-
\((\dfrac{n}{p}) = 1\): n在模p意义下是二次剩余
-
\((\dfrac{n}{p}) = -1\):a在模p意义下是非二次剩余
-
\((\dfrac{n}{p}) = 0\) :\(n\ \% \ p = 0\)
若\(p\)是一个奇素数 , \((\dfrac{n}{p}) = n^ {\frac{p-1}{2} }\)
步骤
因为有解的情况下, 大约有\(\dfrac{p-1}{2}\)个\(a\)满足条件,大约随机数算出的期望是\(2\), 所以就可以放心的随机数了
- \(a = rand() \% p\)
- \(w = a*a - n\)
- \((\dfrac{w}{p}) = w^ {\frac{p-1}{2} }= -1\): \(x = (a +\sqrt{w})^{\frac{p+1}{2}}\)为\((\dfrac{n}{p})\)的解
因为要计算\((a +\sqrt{w})^{\frac{p+1}{2}}\), 可以把\((a +\sqrt{w})^{\frac{p+1}{2}}\)看成两部分来乘(类似于虚数乘法,把\(\sqrt{w}\)看成\(i\))
代码
ll w;
struct Num{
ll x, y;
Num(){
x = y = 0;
}
Num(ll xx, ll yy){
x = xx;
y = yy;
}
Num operator * (Num const & a)const{
Num ans;
ans.x = ((x * a.x)%p + (y * a.y)%p * w %p + p)%p;
ans.y = ((x * a.y)%p + (y * a.x)%p + p)%p;
return ans;
}
};
ll pow_num(Num a, ll b){
Num ans = {1, 0};
while(b){
if(b&1)
ans = ans*a;
a = a*a;
b /= 2;
}
return ans.x%p;
}
ll pow(ll a, ll b){
ll ans = 1;
while(b){
if(b&1)
ans = ans*a%p;
a = a*a%p;
b /= 2;
}
return ans;
}
ll check(ll n){
ll ans = pow(n, (p-1)/2);
if(ans == p-1)
return -1;
else
return 1;
}
ll solve(ll n){
n %= p;
if(check(n) == -1) \\如果当前的check(n) == -1那么就不存在解,返回-1
return -1;
if(p == 2) return n; \\p = 2的时候, n = 0,1。那么x = n
ll a;
srand(time(NULL));
while(1){
a = rand()*13331%p; \\随机数一个a
w = ((a*a%p - n)%p + p)%p;
if(check(w) == -1)
break;
}
Num ans = {a, 1};
return pow_num(ans, (p+1)/2);
}