P5491-[模板]二次剩余

it2024-01-07  59

正题

题目链接:https://www.luogu.com.cn/problem/P5491


题目大意

求解 x 2 = N ( m o d    P ) x^2=N(mod\ \ P) x2=N(mod  P)


解题思路

a a a在模 p p p意义下可以开根那么 a a a就是 p p p的二次剩余,定义 ( a p ) = { 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(ap)1(ap)0(pa)

那么如果 g c d ( a , p ) = 1 gcd(a,p)=1 gcd(a,p)=1就有 ( a p ) = a p − 1 2 \binom{a}{p}=a^{\frac{p-1}2{}} (pa)=a2p1

如果我们求 x 2 = N ( m o d    p ) x^2=N(\mod p) x2=N(modp)那么我们考虑先求一个 ( a 2 − N ) p − 1 2 = − 1 (a^2-N)^{\frac{p-1}{2}}=-1 (a2N)2p1=1,然后定义 ω = a 2 − N \omega=\sqrt{a^2-N} ω=a2N ,那么就有定理 x = ( a + ω ) p + 1 2 x=(a+\omega)^{\frac{p+1}{2}} x=(a+ω)2p+1,这里我们找 a a a的时候只要随机就好了,因为 p p p的二次有 p + 1 2 \frac{p+1}{2} 2p+1个,期望很快就能找到一个合法的 a a a


c o d e code code

#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); } }
最新回复(0)