二次剩余
//二次剩余
//一般是求 x^2=n(mod p) 的解的,其中一般是保证p为奇素数,但是这套板子还处理了2的情况,把素数的情况大部分都包含了
# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
# define random(a,b) (rand()%(b-a+1)+a)
/*
LL mul(LL a,LL b,LL mod)//防止爆LL,会减慢速度
{
LL res=0;
while(b)
{
if(b&1LL) res=(res+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return res;
}
*/
LL quick_pow(LL a,LL b,LL mod)
{
LL ret=1;
while(b)
{
if(b&1LL) ret=ret*a%mod;
a=a*a%mod;
b>>=1;
}
return ret;
}
LL p;
LL w;//二次域的D值
bool ok;//是否有解
struct QuadraticField//二次域
{
LL x,y;
QuadraticField operator*(QuadraticField T)//二次域乘法重载
{
QuadraticField ans;
ans.x=(this->x*T.x%p+this->y*T.y%p*w%p)%p;
ans.y=(this->x*T.y%p+this->y*T.x%p)%p;
return ans;
}
QuadraticField operator^(LL b)//二次域快速幂
{
QuadraticField ans;
QuadraticField a=*this;
ans.x=1;
ans.y=0;
while(b)
{
if(b&1LL)
{
ans=ans*a;
b--;
}
b/=2;
a=a*a;
}
return ans;
}
};
LL Legender(LL a)//求勒让德符号 (a p)=a^((p-1)/2) (mod p)
{
LL ans=quick_pow(a,(p-1)/2,p);
if((ans+1)==p) return -1;//如果ans的值为p-1,那么%p之后会变成-1
else return ans;
}
LL Getw(LL n,LL a)//根据随机出来的a值确定对应w的值
{
return ((a*a-n)%p+p)%p;//防爆处理
}
LL Solve(LL n)
{
LL a;
if(p==2) return n;//当p为2的时候,n只会是0或1,然后0和1就是对应的解
if(Legender(n)==-1) ok=false;//无解
srand((unsigned)time(NULL));
while(1)//随机a,直到a为二次非剩余
{
a=random(0,p-1);
w=Getw(n,a);
if(Legender(w)==-1) break;
}
QuadraticField ans,res;
res.x=a;
res.y=1;//res的值就是a+sqrt(w)
ans=res^((p+1)/2);
return ans.x;
}
int main()
{
int T;
scanf("%d",&T);
LL n,ans1,ans2;
while(T--)
{
scanf("%lld%lld",&n,&p);
if(n==0){
printf("0\n");
continue;
}
ok=true;
n%=p;
ans1=Solve(n);//计算出其中的一个解x
ans2=p-ans1;//另外一个解就是p-x
if(!ok){//无解
printf("Hola!\n");
continue;
}
//输出的解按照升序排列
if(ans1>ans2) swap(ans1,ans2);
if(ans1==ans2) printf("%lld\n",ans1);
else printf("%lld %lld\n",ans1,ans2);
}
return 0;
}
浙公网安备 33010602011771号