又被二次剩余调教了。
以下,p是奇质数。
如果存在一个x,使得 \(x^2=n\; mod \; p\) ,则n是p的一个二次剩余。
勒让德符号: \((\frac{n}{p})\)
当n是p的二次剩余, \((\frac{n}{p})=1\) ;
当n不是p的二次剩余, \((\frac{n}{p})=-1\) ;
当p|n, \((\frac{n}{p})=0\) 。
结论: \((\frac{n}{p})=n^{\frac{p-1}{2}}\) 。
定理:定理:对于方程 \(x^2≡n\; mod \; p\) ,有 \(\frac{p-1}{2}\) 个不同的 n ,使得该方程有解。
所以在[0,p-1]中随机选一个数a,定义w=a^2-n,若 \((\frac{w}{p})=-1\), 那么 \((a+\sqrt{w})^{\frac{p+1}{2}}\) 就是一组二次剩余。
所以这个算法的期望复杂度只有2次。
假如n是p的二次剩余,那么n可以在模p意义下开根。
模板代码:
p是任意的奇质数。
const int p = 1e9 + 7;
struct hh {
ll x, y;
hh() {};
hh(ll _x, ll _y) {
x = _x;
y = _y;
}
};
ll w;
hh mul(hh a, hh b, ll p) {
hh ans;
ans.x = (a.x * b.x % p + a.y * b.y % p * w % p) % p;
ans.y = (a.x * b.y % p + a.y * b.x % p) % p;
return ans;
}
hh quick1(hh a, ll b, ll p) {
hh ans = hh(1, 0);
while(b) {
if(b & 1)
ans = mul(ans, a, p);
a = mul(a, a, p);
b >>= 1;
}
return ans;
}
ll quick2(ll a, ll b, ll p) {
ll ans = 1;
while(b) {
if(b & 1)
ans = (ans * a) % p;
b >>= 1;
a = (a * a) % p;
}
return ans;
}
ll solve(ll a, ll p) { //求解 x^2=a(mod p) 的x的值
a %= p; //注意这句话
if(a == 0)
return 0;//注意这句话
if(p == 2)
return a;
if(quick2(a, (p - 1) / 2, p) == p - 1)
return -1;
ll b, t;
while(1) {
b = rand() % p;
t = b * b - a;
w = (t % p + p) % p;
if(quick2(w, (p - 1) / 2, p) == p - 1)
break;
}
hh ans = hh(b, 1);
ans = quick1(ans, (p + 1) / 2, p);
return ans.x;
}
原文链接:https://blog.csdn.net/kele52he/article/details/78897187
原文链接:https://blog.csdn.net/stevensonson/article/details/85845334