题解 P5491 【【模板】二次剩余】
【一些定义】
1、二次剩余与二次非剩余:对于一个整数
2、勒让德符号:定义如下
图:勒让德符号表
3、欧拉判别准则(Euler's criterion):
Preposition. 费马小定理,拉格朗日定理
证明:由于模数为奇素数,故拉格朗日定理适用:对于任意整数
由于
当
由拉格朗日定理,最多只有
总结一下,即有:
【算法流程】
对于模方程
得到合法的
证明:
若上面一步不懂可用二项式定理理解。
由于
由于费马小定理,
所以:
证毕。
啊但是
类似复数的想法,我们可以扩展数域,搞出一个模
如果这个虚数虚部不是零?事实上不会。
证明:设最终获得的二次剩余为
故
若
那只找到了一个解啊,还有一个解呢?实际上另一个解就是
【代码】
#include <bits/stdc++.h>
#define _rep(i, x, y) for(int i = x; i <= y; i++)
#define _per(i, x, y) for(int i = x; i >= y; i--)
#define LL long long
#define ULL unsigned long long
#define LD long double
using namespace std;
template <typename T>
inline void read(T &x) {
x = 0; T f = (T) 1;
char c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - 48;
x *= f;
}
template <typename T>
inline void write(T x) {
if(x < 0) {putchar('-'); x = -x;}
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T>
inline void writesp(T x, char sp = '\n') {
write(x); putchar(sp);
}
int T, n, p, omega, WJP_AK_IOI = 1;
struct cpx {
int real, imag;
void init(int r, int i) {real = r; imag = i;}
};
cpx multiply(cpx a, cpx b) {
cpx Z;
Z.init((1ll * a.real * b.real % p + 1ll * a.imag * b.imag % p * omega % p) % p, (1ll * a.real * b.imag % p + 1ll * b.real * a.imag % p) % p);
return Z;
}
int pow_mod(int a, int b, int p) {
int ans = 1;
while(b) {
if(b & 1) ans = 1ll * ans * a % p;
a = 1ll * a * a % p;
b >>= 1;
}
return ans;
}
cpx pow_cpx(cpx a, int b) {
cpx Ans; Ans.init(1, 0);
while(b) {
if(b & 1) Ans = multiply(Ans, a);
a = multiply(a, a);
b >>= 1;
}
return Ans;
}
int legendre(int n, int p) {
if(!(n % p)) return 0;
return pow_mod(n, (p - 1) / 2, p);
}
int quad_residue(int n, int p) {
n %= p;
if(legendre(n, p) == p - 1) return -1;
int A;
while(1) {
A = rand() % p;
omega = (1ll * A * A % p - n + p) % p;
if(legendre(omega, p) == p - 1) break;
}
cpx I; I.init(A, 1);
cpx Q = pow_cpx(I, (p + 1) / 2);
return Q.real;
}
int main() {
srand(time(0));
read(T);
while(T--) {
read(n); read(p);
if(!n) {writesp(n, '\n'); continue;}
int k = quad_residue(n, p);
if(k == -1) {
puts("Hola!");
} else {
int k2 = p - k;
if(k > k2) swap(k, k2);
if(k == k2) cout << k << endl;
else cout << k << " " << k2 << endl;
}
}
return 0;
}
【参考资料】
1、Magolor - 数论 PPT
2、【注:使用镜像】Wikipedia: Quadratic non-residue
3、【注:使用镜像】Wikipedia: Legendre Symbol