P5491 【模板】二次剩余

Summary

实际上是做法的归纳
一切皆是结论性的,没有证明!

p 意义下的二次剩余有 p12 个,二次非剩余也恰有那么多

考虑解关于 x 的同余方程

x2n(modp)

n=0 时,x=0 是唯一解
n0 时,若方程有解,则只有两个互为相反数的解
判断有无解:欧拉准则
考虑 np12p 的结果
(np12)21(modp)
只其结果只为 11
1 时有解,1 时无解

求解的话,先随机找到一个 a 满足 a2n 为二次非剩余,令 i2=a2n1(modp)
类似实部和虚部,定义这个 i

(a+i)p+1n(modp)

证明的话,有
Lemma 1

ipi(modp)

Lemma 2

(x+y)pxp+yp(modp)

然后

(a+i)p+1(a+i)p(a+i)(a+i)(ap+ip)(a+i)(ai)a2i2n(modp)

p+1 为偶数,开方就很容易了
具体实现弄上“复数”即可
(a+i)p+12 的“虚部” 为 0

Code

#include <cstdio>
#include <algorithm>
#include <iostream>
#define IN inline
using namespace std;
typedef long long LL;
int T, n, p;
LL i2;
struct complex {
LL x, y;
IN complex(LL _x, LL _y) {x = _x, y = _y;}
IN bool operator == (complex a) {return (a.x == x && a.y == y);}
IN complex operator * (complex a) {
return complex((a.x * x % p + a.y * y % p * i2 % p) % p, (a.x * y % p + a.y * x % p) % p);
}
};
IN complex power(complex x, int y) {
complex s = complex(1, 0);
for(; y; y >>= 1, x = x * x) if (y & 1) s = s * x;
return s;
}
IN int check(LL a) {return power(complex(a, 0), p - 1 >> 1) == complex(1, 0);}
IN void solve() {
if (!n) {printf("0\n"); return;}
if (power(complex(n, 0), p - 1 >> 1) == complex(p - 1, 0)) {printf("Hola!\n"); return;}
LL a = rand() % p;
while (!a || check((a * a % p - n + p) % p)) a = rand() % p;
i2 = (a * a % p - n + p) % p;
int x0 = power(complex(a, 1), p + 1 >> 1).x, x1 = p - x0;
if (x0 > x1) swap(x0, x1);
printf("%d %d\n", x0, x1);
}
int main() {
scanf("%d", &T);
for(; T; --T) scanf("%d%d", &n, &p), solve();
}
posted @   leiyuanze  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
历史上的今天:
2021-07-15 LG P4213【模板】杜教筛(Sum)
2020-07-15 JZOJ 排列统计
点击右上角即可分享
微信分享提示