看 ( ext{yyb}) 的博客看到的,发现似乎并没有想象中的那么难,就学了一下,过了板题,这里记录一下,暂时还是只会二次剩余, (n) 次剩余暂时先放一下。
模数为奇素数
下文的 (p) 即是模数。
我们称 (n) 为模 (p) 意义下的二次剩余当且仅当存在 (x) 使得 (x^2equiv npmod p,xin mathbb{N}) 。下文的 (mathbb{N}) 其实是自然数集。
- 引理1
((A+B)^pequiv A^p+B^ppmod{p})
- 证明
显然只需要说明 (dbinom{p}{i}equiv0pmod p,s.t. 1le ile p-1),然后我们发现如果 (p) 是个奇素数的话,那么分子里面的 (p) 就没有办法消去,于是就得证了。
- 引理2
(n^{frac{p-1}{2}}equiv 1pmod p)
是 (n) 是模 (p) 意义下的二次剩余的充要条件。
- 证明
必要性 :设 (x^2equiv npmod p),那么有 (x^{p-1}equiv 1pmod p) ,证毕。
充分性 :显然。
接下来,我们考虑随机出一个 (a) 使得 (a^2-n) 不是一个二次剩余,这样的期望尝试次数大概为 (2),再设 (i^2=a^2-n) ,这里的 (i) 显然就不属于 (mathbb{N}) ,我们把它视作虚数之类的东西就好了。然后我们发现就有个性质:
- 性质
证明 :首先我们知道 ((i^2)^{frac{p-1}{2}}equiv (a^2-n)^{frac{p-1}{2}} otequiv 1pmod p) (因为 (a^2-n) 不是一个二次剩余),然后又有 ((i^2)^{p-1}equiv 1pmod p),所以 (i^{p-1}equiv -1pmod p)。
我们可(bu)以(neng)发现:
就是说 ((a+i)^{p+1}equiv npmod p),所以说 (sqrt nequiv (a+i)^{frac{p+1}{2}}pmod p)。
可能有人有疑问,((a+i)^{frac{p+1}{2}}) 有没有可能不是一个整数,显然如果你保证有解的话它显然就是一个整数。
( exttt{Code})
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define int long long
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
int p,sqri;
int qkpow (int a,int b){
int res = 1;for (;b;b >>= 1,a = 1ll * a * a % p) if (b & 1) res = 1ll * res * a % p;
return res;
}
int mul (int a,int b){return 1ll * a * b % p;}
int dec (int a,int b){return a >= b ? a - b : a + p - b;}
int add (int a,int b){return a + b >= p ? a + b - p : a + b;}
struct node{
int real,imag;
node (int _real,int _imag) : real (_real) , imag (_imag) {}
node operator * (node b){return node (add (1ll * real * b.real % p,1ll * imag * b.imag % p * sqri % p),add (1ll * real * b.imag % p,1ll * b.real * imag % p));}
node operator + (node b){return node (add (real,b.real),add (imag,b.imag));}
node operator ^ (int b){node a = *this,res = node (1,0);for (;b;b >>= 1,a = a * a) if (b & 1) res = res * a;return res;}
};
bool check_if_qs (int n){//判断是否是一个二次剩余
return qkpow (n,(p - 1) >> 1) == 1;
}
bool tryit (int n){
if (n == 0){
puts ("0");
return 1;
}
int a = rand ();sqri = dec (mul (a,a),n);
if (!a || !check_if_qs (sqri)){
int x0 = (node (a,1) ^ (p + 1 >> 1)).real;
int x1 = p - x0;if (x0 > x1) swap (x0,x1);
write (x0),putchar (' '),write (x1),putchar ('
');
return 1;
}
else return 0;
}
signed main(){
int T;read (T);
while (T --> 0){
int n;read (n,p);
if (!check_if_qs (n) && n) puts ("Hola!");
else while (1) if (tryit (n)) break;
}
return 0;
}