1. 程式人生 > 實用技巧 >二次剩餘模板

二次剩餘模板

 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 }