二次剩余
门
俗称膜意义下开根
证明等一系列看懂了,但之后还是不会退,所以背板吧QAQ
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int mod;
int add(int a,int b) {return a+b>=mod?a+b-mod:a+b;}
int del(int a,int b) {return a<b?a+mod-b:a-b;}
int mul(int a,int b) {return 1ll*a*b%mod;}
int quick_mul(int a,int k,int ans=1){for(;k;k>>=1,a=mul(a,a))if(k&1)ans=mul(ans,a);return ans;}
int w;
struct nd{
int x,y;
nd(){}
nd(int a,int b){x=a;y=b;}
nd operator*(const nd &a)const{return nd(add(mul(x,a.x),mul(mul(y,a.y),w)),add(mul(x,a.y),mul(y,a.x)));}
};
nd quick_mul(nd a,int k,nd ans=nd(1,0)){for(;k;k>>=1,a=a*a)if(k&1)ans=ans*a;return ans;}
bool check_sqrt(int a){return quick_mul(a,(mod-1)/2)==1;}
int get_w(int n)
{
for(int a=rand();;a=rand())
if(!check_sqrt(del(mul(a,a),n)))
return w=del(mul(a,a),n),a;
}
void get_sqrt(int n,int &x1,int &x2)
{
int a=get_w(n);
x1=(quick_mul(nd(a,1),(mod+1)/2)).x;
x2=mod-x1;
}
int n;
int main()
{
srand(time(0));
int x1,x2,T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&mod);
if(!n){printf("0\n");continue;}
if(!check_sqrt(n)){printf("Hola!\n");continue;}
get_sqrt(n,x1,x2);
if(x1>x2)swap(x1,x2);
if(x1!=x2)printf("%d %d\n",x1,x2);
else printf("%d\n",x1);
}
}