正题
题目链接:https://www.luogu.com.cn/problem/P5491
题目大意
求解x2=N(modP)x^2=N(mod\ \ P)x2=N(mod P)
解题思路
若aaa在模ppp意义下可以开根那么aaa就是ppp的二次剩余,定义
(ap)={1(a是p的二次剩余)−1(a是p的二次非剩余)0(p∣a)\binom{a}{p}=\left\{\begin{matrix}1(a是p的二次剩余)\\-1(a是p的二次非剩余)\\0(p|a)\end{matrix}\right.(pa)=⎩⎨⎧1(a是p的二次剩余)−1(a是p的二次非剩余)0(p∣a)
那么如果gcd(a,p)=1gcd(a,p)=1gcd(a,p)=1就有(ap)=ap−12\binom{a}{p}=a^{\frac{p-1}2{}}(pa)=a2p−1。
如果我们求x2=N(modp)x^2=N(\mod p)x2=N(modp)那么我们考虑先求一个(a2−N)p−12=−1(a^2-N)^{\frac{p-1}{2}}=-1(a2−N)2p−1=−1,然后定义ω=a2−N\omega=\sqrt{a^2-N}ω=a2−N,那么就有定理x=(a+ω)p+12x=(a+\omega)^{\frac{p+1}{2}}x=(a+ω)2p+1,这里我们找aaa的时候只要随机就好了,因为ppp的二次有p+12\frac{p+1}{2}2p+1个,期望很快就能找到一个合法的aaa。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll T,n,p,k,w;
struct complex{complex(ll xx=0,ll yy=0){x=xx;y=yy;}ll x,y;
};
complex operator+(complex &a,complex &b)
{return complex((a.x+b.x)%p,(a.y+b.y)%p);}
complex operator-(complex &a,complex &b)
{return complex((a.x-b.x+p)%p,(a.y-b.y+p)%p);}
complex operator*(complex &a,complex &b)
{return complex((a.x*b.x%p+a.y*b.y%p*w%p+p)%p,(a.x*b.y+a.y*b.x)%p);}
complex poweri(complex x,ll b){complex ans=complex(1,0);while(b){if(b&1)ans=ans*x;x=x*x;b>>=1; }return ans;
}
ll power(ll x,ll b){ll ans=1;while(b){if(b&1)ans=ans*x%p;x=x*x%p;b>>=1;}return ans;
}
bool check(ll a)
{return power(((a*a%p-n)%p+p)%p,k)==(p-1);}
int main()
{srand(31958);scanf("%lld",&T);while(T--){scanf("%lld%lld",&n,&p);if(!n){printf("0\n");continue;}if(p==2){printf("%lld\n",n);continue;}k=(p-1)>>1;if(power(n,k)==p-1){printf("Hola!\n");continue;}ll a=rand()%p;while(!check(a))a=rand()%p;w=((a*a%p-n)%p+p)%p;ll x1=poweri(complex(a,1),(p+1)/2).x;ll x2=p-x1;if(x1>x2)swap(x1,x2);if(x1!=x2)printf("%lld %lld\n",x1,x2);else printf("%lld\n",x1);}
}