算法来源:https://en.wikipedia.org/wiki/Cipolla%27s_algorithm
上代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
ll P(ll a,ll b,ll mod)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans;
}
ll w,m;
struct R
{
ll x,y;
R(ll _x,ll _y)
{
x=_x;
y=_y;
}
R operator*(const R & a)
{
return R((x*a.x%m+y*a.y%m*w%m)%m,(x*a.y%m+y*a.x%m)%m);
}
};
R P(R a,ll b)
{
R ans(1,0);
while(b)
{
if(b&1)ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
ll legendre(ll a,ll p)
{
return P(a,(p-1)>>1,p);
}
ll solve(ll n,ll p)
{
if(legendre(n,p)+1==p) return -1;
ll a;
ll t;
for(;;)
{
a=rand()%p;
t=(a*a-n)%p;
if(t<0)t+=p;
if(legendre(t,p)+1==p)break;
}
w=t;
//cout<<"w: "<<w<<endl;
//cout<<"a: "<<a<<endl;
R A(a,1);
R ans=P(A,(p+1)>>1);
return ans.x;
}
int main()
{
int t;
cin>>t;
ll n,p;
while(t--)
{
scanf("%lld%lld",&n,&p);
n%=p;
if(p==2) cout<<1<<endl;
else
{
m=p;
ll ans=solve(n,p);
if(ans==-1)
printf("No root\n");
else
{
ll _ans=p-ans;
if(_ans<ans)
swap(_ans,ans);
printf("%lld %lld\n",ans,_ans);
}
}
}
return 0;
}