二次剩餘模板
阿新 • • 發佈:2020-08-16
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 int t; 6 ll n, p; 7 ll w; 8 9 struct num { //建立一個複數域 10 11 ll x, y; 12 }; 13 14 num mul(num a, num b, ll p) { //複數乘法 15 num ans = {0, 0}; 16 ans.x = ((a.x * b.x % p + a.y * b.y % p * w % p) % p + p) % p;17 ans.y = ((a.x * b.y % p + a.y * b.x % p) % p + p) % p; 18 return ans; 19 } 20 21 ll binpow_real(ll a, ll b, ll p) { //實部快速冪 22 ll ans = 1; 23 while (b) { 24 if (b & 1) ans = ans * a % p; 25 a = a * a % p; 26 b >>= 1; 27 } 28 return ans % p; 29 } 30 31 ll binpow_imag(num a, ll b, ll p) { //虛部快速冪 32 num ans = {1, 0}; 33 while (b) { 34 if (b & 1) ans = mul(ans, a, p); 35 a = mul(a, a, p); 36 b >>= 1; 37 } 38 return ans.x % p; 39 } 40 41 ll cipolla(ll n, ll p) { 42 n %= p; 43 if (p == 2) return n; 44 if (binpow_real(n, (p - 1) / 2, p) == p - 1) return -1; 45 ll a; 46 while (1) { //生成隨機數再檢驗找到滿足非二次剩餘的a 47 a = rand() % p; 48 w = ((a * a % p - n) % p + p) % p; 49 if (binpow_real(w, (p - 1) / 2, p) == p - 1) break; 50 } 51 num x = {a, 1}; 52 return binpow_imag(x, (p + 1) / 2, p); 53 }