【模板】二次剩余
大佬的blog
具体看blog吧,这里只是列出代码需要用到的。
欧拉准则:
定义
解为
随机a之后暴力判断即可,这样期望2次就可以找到a。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int mul_i,x0,x1,n,mod;
struct CP {
int x,y;
CP(int xx=0,int yy=0) {
x=xx; y=yy;
}
CP operator * (const CP&A) const {
return CP((x*A.x%mod+y*A.y%mod*mul_i%mod)%mod,(x*A.y%mod+y*A.x%mod)%mod);
}
};
CP Ipow(CP x,int y) {
CP res(1,0);
while(y) {
if(y&1) res=res*x;
x=x*x; y>>=1;
}
return res;
}
int fpow(int x,int y) {
x%=mod; int res=1;
while(y) {
if(y&1) (res*=x)%=mod;
(x*=x)%=mod; y>>=1;
}
return res;
}
bool check(int x) {
return fpow(x,(mod-1)>>1)==1;
}
void solve() {
int a=rand()%mod;
while(!a||check((a*a+mod-n)%mod)) a=rand()%mod;
// cout<<a<<endl;
mul_i=(a*a+mod-n)%mod;
x0=Ipow(CP(a,1),(mod+1)>>1).x;
x1=mod-x0;
}
int rd() {
int f=1,sum=0; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
signed main() {
srand(time(0));
srand((rand()*2)*(rand()*3));
int t;
t=rd();
while(t--) {
n=rd(); mod=rd();
if(!n) {
puts("0");
continue;
}
if(!check(n)) {
puts("Hola!");
continue;
}
solve();
if(x0==x1) printf("%lld\n",x0);
else if(x0<x1) printf("%lld %lld\n",x0,x1);
else printf("%lld %lld\n",x1,x0);
}
}