二次剩余
勒让德符号(Wikipedia)
[{displaystyle left({frac {a}{p}}
ight)={egin{cases}1&{ ext{if }}a{ ext{ is a quadratic residue modulo }}p{ ext{ and }}a
ot equiv 0{pmod {p}},\-1&{ ext{if }}a{ ext{ is a non-quadratic residue modulo }}p,\0&{ ext{if }}aequiv 0{pmod {p}}.end{cases}}}
]
定理0
在模(p)意义下,分别有(frac{p-1}{2})个二次剩余和非二次剩余。
定理1
[left({frac {a}{p}}
ight) equiv a^{frac{p-1}2}pmod p
]
(仿定理0)
Cipolla 算法
- 假设要求(x^2equiv npmod p),随机一个数(a),使得(a^2-n)为非二次剩余。
- 设(w=sqrt{a^2-n}),构造一个所有数都可以表示成(a+bw)的域(mathbb F_{p^2})(?)。
- 则一个可行的(xequiv(a+w)^{frac{p+1}2}pmod p)。快速幂即可求。
定理2
[w^p=-wpmod p
]
定理3
[forall x, yin mathbb F_{p^2}:
(x+y)^pequiv x^p+y^ppmod p
]
定理4
[(a+w)^{p+1}equiv npmod p
]
代码
#include <bits/stdc++.h>
#define int ll
using namespace std;
typedef long long ll;
int t, n, p, a, w;
ostream& operator <<(ostream &, struct p2);
struct p2{
ll a, b;
p2 operator *(const p2 &q) {
return (p2){(a*q.a+b*q.b%p*w)%p, (a*q.b+b*q.a)%p};
}
p2 operator %(const int p) {
return (p2){a%p, b%p};
}
};
template<typename T>
T qpow(T a, int x, T e) {
return (x?(qpow(a*a%p, x/2, e)*(x&1?a:e)):e)%p;
}
signed main() {
cin >> t;
while (t--) {
cin >> n >> p;
int tmp = qpow<ll>(n, (p-1)/2, 1);
if (tmp == 0) {
cout << 0 << endl;
continue;
} else if (tmp == p-1) {
cout << "Hola!
";
continue;
}
do {
a = rand()%p;
} while (qpow<ll>(w=((ll)a*a+p-n)%p, (p-1)/2, 1) != p-1);
p2 x = qpow((p2){a/*注意这里的a……调了半天*/, 1}, (p+1)/2, (p2){1,0});
cout << min(p-x.a, x.a) << ' ' << max(p-x.a, x.a) << endl;
}
}