关于二次剩余的介绍:http://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm
二次剩余的模版:
inline ll pow_mod(ll a,ll k,ll mo)
{
ll ans=1;
while(k)
{
if(k%2) ans=ans*a%mo;
a=a*a%mo;
k>>=1;
}
return ans%mo;
}
inline int modsqr(int a,int n)
{
int b,k,i,x;
if(n==2) return a%n;
if(pow_mod(a,(n-1)/2,n)==1)
{
if(n%4==3)
x=pow_mod(a,(n+1)/4,n);
else
{
for(b=1;pow_mod(b,(n-1)/2,n)==1;b++);
i=(n-1)/2;
k=0;
do{
i/=2;
k/=2;
if((pow_mod(a,i,n)*(ll)pow_mod(b,k,n)+1)%n==0)
k+=(n-1)/2;
}while(i%2==0);
x=(pow_mod(a,(i+1)/2,n)*(ll)pow_mod(b,k/2,n))%n;
}
if(x*2>n) x=n-x;
return x;
}
return -1;
}
此题在n==2的时候特判一下答案就可以了。
#include<cstdio>
#define ll long long
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline ll pow_mod(ll a,ll k,ll mo)
{
ll ans=1;
while(k)
{
if(k%2) ans=ans*a%mo;
a=a*a%mo;
k>>=1;
}
return ans%mo;
}
inline int modsqr(int a,int n)
{
int b,k,i,x;
if(n==2) return a%n;
if(pow_mod(a,(n-1)/2,n)==1)
{
if(n%4==3)
x=pow_mod(a,(n+1)/4,n);
else
{
for(b=1;pow_mod(b,(n-1)/2,n)==1;b++);
i=(n-1)/2;
k=0;
do{
i/=2;
k/=2;
if((pow_mod(a,i,n)*(ll)pow_mod(b,k,n)+1)%n==0)
k+=(n-1)/2;
}while(i%2==0);
x=(pow_mod(a,(i+1)/2,n)*(ll)pow_mod(b,k/2,n))%n;
}
if(x*2>n) x=n-x;
return x;
}
return -1;
}
int main()
{
int a,n,t;
t=read();
while(t--)
{
a=read();n=read();
int ans=modsqr(a,n);
if(ans==-1) puts("No root");
else if(n==2) puts("1");
else printf("%d %d\n",ans,n-ans);
}
}