ThoneLLi_Shanks算法
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll pow_mod(ll a,ll b,ll c) {
ll ans = 1; a = a % c;
while (b) {
if (b & 1) ans = ans * a % c;
b >>= 1; a = a * a % c;
}
return ans;
}
ll ToneLLi_Shanks(ll n,ll p) {
if (p == 2) return (n & 1) ? 1 : -1;
if (pow_mod(n, p>>1, p) != 1) return -1;
if (p & 2) return pow_mod(n, p + 1 >> 2, p);
int s = __builtin_ctzll(p ^ 1);
ll q = p >> s,z = 2;
for (; pow_mod(z, p >> 1, p) == 1; ++z);
ll c = pow_mod(z, q, p);
ll r = pow_mod(n, q + 1 >> 1, p);
ll t = pow_mod(n, q, p), tmp;
for (int m = s, i; t != 1; ++i) {
for (i = 0, tmp = t; tmp != 1; ++i) tmp = tmp * tmp % p;
for(; i < --m;) c = c * c % p;
r = r * c % p;
c = c * c % p;
t = t * c % p;
}
return r;
}
int main() {
int T; cin >> T;
while (T--) {
int n, p; cin >> n >> p;
int ans = ToneLLi_Shanks(n, p);
if (ans == -1) {
puts("No root");
} else if (ans * 2 == p) {
cout << ans << endl;
} else {
cout << min(ans, p - ans) << " " << max(ans, p - ans) << endl;
}
}
return 0;
}
Cipolla 算法
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll p, w, n;
struct Quadratic{
ll x, y;
Quadratic () {};
Quadratic(ll x,ll y) {
this->x = x;
this->y = y;
}
};
Quadratic multi(Quadratic a,Quadratic b,ll c) {
Quadratic ans;
ans.x = (a.x * b.x % c + a.y * b.y % c * w % c) % c;
ans.y = (a.x * b.y % c + a.y * b.x % c) % c;
return ans;
}
Quadratic quick_pow(Quadratic a,ll b,ll c) {
Quadratic ans = Quadratic(1, 0);
while (b) {
if (b & 1) ans = multi(ans, a, c);
a = multi(a, a, c); b >>= 1;
}
return ans;
}
ll pow_mod(ll a,ll b,ll c) {
ll ans = 1; a = a % c;
while (b) {
if (b & 1) ans = ans * a % c;
b >>= 1; a = a * a % c;
}
return ans;
}
ll Cipolla(ll n,ll p) {
n %= p; ll b, t;
if (n == 0) return 0;
if (p == 2) return n;
if (pow_mod(n, p - 1 >> 1, p) == p - 1) return -1;
while (true) {
b = rand() % p;
t = b * b - n;
w = (t % p + p) % p;
if (pow_mod(w, p - 1 >> 1, p) == p - 1) break;
}
Quadratic ans = Quadratic(b, 1);
ans = quick_pow(ans, p + 1 >> 1, p);
return ans.x;
}
int main() {
int T; cin >> T;
while (T--) {
cin >> n >> p;
ll ans = Cipolla(n, p);
if (ans == -1) puts("No root");
else if (ans * 2 == p) cout << ans << endl;
else cout << min(ans, p-ans) << " " << max(ans, p-ans) << endl;
}
return 0;
}