# 二次剩余

### 二次剩余

$x^2 = n$

$$$\left(\frac{n}{P}\right) = \begin{cases}0& \mbox{if P | n}\\1&\mbox{if \exist a , a^2\equiv x \pmod P}\\-1&\mbox{if \not \exist a,a^2\equiv x \pmod P}\end{cases}$$$

$\left(\frac{n}{P}\right) \equiv n^{\frac{P-1}{2}} \pmod P$

$( a + \sqrt x )^{P} \equiv a^P + \sqrt x ^ P \equiv a - \sqrt x \pmod P$

$(a + \sqrt x)^{P+1} \equiv a^2 - x \pmod P$

$(a + \sqrt{a^2 - n})^{P+1} \equiv n \pmod P$

#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
using namespace std;
#define MAXN 100006

int n , P;
int i2;
struct comp {
int a , b;
comp( int a , int b ) : a(a) , b(b) {}
};
comp operator *( comp a , comp b ) { return comp( ( 1ll * a.a * b.a % P + 1ll * a.b * b.b % P * i2 % P ) % P , ( 1ll * a.a * b.b % P + 1ll * a.b * b.a % P ) % P ); }
comp Pow( comp a , int x ) {
comp ans( 1 , 0 );
while( x ) {
if( x & 1 ) ans = ans * a;
a = a * a , x >>= 1;
}
return ans;
}
int work( ) {
if( n == 0 ) return 0;
if( P == 2 && n == 1 ) return 1;
if( n >= P || Pow( comp(n , 0) , (P - 1) / 2 ).a == P - 1 ) return -1;
int t;
for( t = rand() % P + 1 ; ; t = rand() % P + 1 ) {
i2 = ( 1ll * t * t % P - n + P) % P;
if( Pow( comp( i2 , 0 ) , ( P - 1 ) / 2 ).a != P - 1 ) continue;
break;
}
comp ans = Pow( comp( t , 1 ) , ( P + 1 ) / 2 );
return min( ans.a , P - ans.a );
}

int main() {
srand( time( 0 ) );
int T;cin >> T;
while( T-- ) {
scanf("%d%d",&n,&P);
int ans = work( );
if( ans > 0 ) printf("%d %d\n",ans , P - ans);
else if( ans == 0 ) puts( "0" );
else puts("Hola!");
}
}

posted @ 2020-02-25 13:49  yijan  阅读(154)  评论(0编辑  收藏  举报