二次剩余
参考资料。
类似fft,自定义一种复数,使得第二维的平方等于w。
然后就可以进行SAO操作了。
注意sgn要返回long long
1 #include <cstdio> 2 #include <algorithm> 3 #include <climits> 4 5 typedef long long LL; 6 const int N = 100010; 7 8 LL w, MO; 9 10 inline int rd() { 11 return (rand() * (1ll << 16) + rand()) % LONG_MAX; 12 } 13 14 struct cp { 15 LL x, y; 16 cp(LL X = 0, LL Y = 0) { 17 x = X; 18 y = Y; 19 } 20 inline cp operator *(const cp &W) const { 21 return cp(x * W.x % MO + y * W.y % MO * w % MO, x * W.y % MO + y * W.x % MO); 22 } 23 inline cp operator %(const LL &W) const { 24 return cp(x % W, y % W); 25 } 26 }; 27 28 template <class T> inline T qpow(T a, LL b) { 29 T ans(1); 30 while(b) { 31 if(b & 1) ans = ans * a % MO; 32 a = a * a % MO; 33 b = b >> 1; 34 } 35 return ans; 36 } 37 38 inline int sgn(LL x) { 39 return qpow(x, (MO - 1) >> 1); 40 } 41 42 inline void solve() { 43 LL n; 44 scanf("%lld%lld", &n, &MO); 45 n %= MO; 46 if(MO == 2) { 47 printf("%d\n", n); 48 return; 49 } 50 if(sgn(n) == MO - 1) { 51 printf("No root\n"); 52 return; 53 } 54 LL a; 55 while(1) { 56 a = rd() % MO; 57 w = (a * a % MO - n + MO) % MO; 58 if(sgn(w) == MO - 1) break; 59 } 60 cp ans(a, 1); 61 ans = qpow(ans, (MO + 1) >> 1); 62 LL b = ans.x, c = MO - b; 63 if(b > c) std::swap(b, c); 64 printf("%lld %lld \n", b, c); 65 return; 66 } 67 68 int main() { 69 srand(19384); 70 int T; 71 scanf("%d", &T); 72 while(T--) solve(); 73 return 0; 74 }