二次剩余
存在 (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);
}