二次剩余模板
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int t;
ll n, p;
ll w;
struct num { //建立一个复数域
ll x, y;
};
num mul(num a, num b, ll p) { //复数乘法
num ans = {0, 0};
ans.x = ((a.x * b.x % p + a.y * b.y % p * w % p) % p + p) % p;
ans.y = ((a.x * b.y % p + a.y * b.x % p) % p + p) % p;
return ans;
}
ll binpow_real(ll a, ll b, ll p) { //实部快速幂
ll ans = 1;
while (b) {
if (b & 1) ans = ans * a % p;
a = a * a % p;
b >>= 1;
}
return ans % p;
}
ll binpow_imag(num a, ll b, ll p) { //虚部快速幂
num ans = {1, 0};
while (b) {
if (b & 1) ans = mul(ans, a, p);
a = mul(a, a, p);
b >>= 1;
}
return ans.x % p;
}
ll cipolla(ll n, ll p) {
n %= p;
if (p == 2) return n;
if (binpow_real(n, (p - 1) / 2, p) == p - 1) return -1;
ll a;
while (1) { //生成随机数再检验找到满足非二次剩余的a
a = rand() % p;
w = ((a * a % p - n) % p + p) % p;
if (binpow_real(w, (p - 1) / 2, p) == p - 1) break;
}
num x = {a, 1};
return binpow_imag(x, (p + 1) / 2, p);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld",&n,&p);
if(!n)
{
puts("0");
continue;
}
else
{
ll x1=cipolla(n,p),x2;
if(x1==-1)
{
puts("Hola!");
}
else
{
x2=p-x1;
if(x1==x2) printf("%lld\n",x1);
else
{
if(x1>x2) swap(x1,x2);
printf("%lld %lld\n",x1,x2);
}
}
}
}
return 0;
}