結果
問題 | No.981 一般冪乗根 |
ユーザー | 37zigen |
提出日時 | 2020-02-13 17:12:27 |
言語 | C++14 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 6 ms / 6,000 ms |
コード長 | 6,314 bytes |
コンパイル時間 | 1,239 ms |
コンパイル使用メモリ | 106,684 KB |
実行使用メモリ | 5,248 KB |
最終ジャッジ日時 | 2024-10-09 23:45:06 |
合計ジャッジ時間 | 52,344 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 5 ms
5,248 KB |
testcase_01 | AC | 4 ms
5,248 KB |
testcase_02 | AC | 4 ms
5,248 KB |
testcase_03 | AC | 4 ms
5,248 KB |
testcase_04 | AC | 4 ms
5,248 KB |
testcase_05 | AC | 3 ms
5,248 KB |
testcase_06 | AC | 3 ms
5,248 KB |
testcase_07 | AC | 3 ms
5,248 KB |
testcase_08 | AC | 3 ms
5,248 KB |
testcase_09 | AC | 3 ms
5,248 KB |
testcase_10 | AC | 3 ms
5,248 KB |
testcase_11 | AC | 3 ms
5,248 KB |
testcase_12 | AC | 3 ms
5,248 KB |
testcase_13 | AC | 3 ms
5,248 KB |
testcase_14 | AC | 3 ms
5,248 KB |
testcase_15 | AC | 4 ms
5,248 KB |
testcase_16 | AC | 3 ms
5,248 KB |
testcase_17 | AC | 3 ms
5,248 KB |
testcase_18 | AC | 3 ms
5,248 KB |
testcase_19 | AC | 3 ms
5,248 KB |
testcase_20 | AC | 4 ms
5,248 KB |
testcase_21 | AC | 4 ms
5,248 KB |
testcase_22 | AC | 4 ms
5,248 KB |
testcase_23 | AC | 3 ms
5,248 KB |
testcase_24 | AC | 4 ms
5,248 KB |
testcase_25 | AC | 5 ms
5,248 KB |
testcase_26 | AC | 5 ms
5,248 KB |
testcase_27 | AC | 3 ms
5,248 KB |
testcase_28 | AC | 6 ms
5,248 KB |
evil_60bit1.txt | AC | 191 ms
5,248 KB |
evil_60bit2.txt | AC | 184 ms
5,248 KB |
evil_60bit3.txt | AC | 191 ms
5,248 KB |
evil_hack | RE | - |
evil_hard_random | AC | 178 ms
5,248 KB |
evil_hard_safeprime.txt | AC | 329 ms
5,248 KB |
evil_hard_tonelli0 | AC | 142 ms
5,248 KB |
evil_hard_tonelli1 | AC | 475 ms
5,248 KB |
evil_hard_tonelli2 | AC | 176 ms
5,248 KB |
evil_hard_tonelli3 | AC | 148 ms
5,248 KB |
evil_sefeprime1.txt | AC | 328 ms
5,248 KB |
evil_sefeprime2.txt | AC | 329 ms
5,248 KB |
evil_sefeprime3.txt | AC | 330 ms
5,248 KB |
evil_tonelli1.txt | AC | 709 ms
5,248 KB |
evil_tonelli2.txt | AC | 710 ms
5,248 KB |
ソースコード
#include <cstdio> #include <cassert> #include <cmath> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <map> #include <set> #include <functional> #include <stack> #include <queue> #include <tuple> using namespace std; using i64 = long long; using u8 = unsigned char; using u32 = unsigned; using u64 = unsigned long long; using f80 = long double; using i128 = __int128_t; using u128 = __uint128_t; struct Mod64 { Mod64() : x(0) {} Mod64(u64 n) : x(init(n)) {} static u64 modulus() { return mod; } static u64 init(u64 w) { return reduce(u128(w) * r2); } static void set_mod(u64 m) { mod = m; assert(mod & 1); inv = m; for (int i = 0; i < 5; ++i) inv *= 2 - inv * m; r2 = -u128(m) % m; } static u64 reduce(u128 x) { u64 y = u64(x >> 64) - u64((u128(u64(x) * inv) * mod) >> 64); return i64(y) < 0 ? y + mod : y; } u64 get() const { return reduce(x); } void set(u64 n) { x = n; } Mod64 pow(u64 e) const { Mod64 ret = Mod64(1); for (Mod64 b = *this; e; e >>= 1, b *= b) if (e & 1) ret *= b; return ret; } Mod64 inverse() const { return pow(mod - 2); } Mod64& operator += (Mod64 rhs) { if (i64(x += rhs.x - mod) < 0) x += mod; return *this; } Mod64& operator -= (Mod64 rhs) { if (i64(x -= rhs.x) < 0) x += mod; return *this; } Mod64& operator *= (Mod64 rhs) { x = reduce(u128(x) * rhs.x); return *this; } Mod64 operator + (Mod64 rhs) const { return Mod64(*this) += rhs; } Mod64 operator - (Mod64 rhs) const { return Mod64(*this) -= rhs; } Mod64 operator * (Mod64 rhs) const { return Mod64(*this) *= rhs; } bool operator == (const Mod64& rhs) const { return x == rhs.x; } bool operator != (const Mod64& rhs) const { return x != rhs.x; } friend ostream& operator << (ostream& os, const Mod64& m) { return os << m.get(); } // ... int operator & (int t) const { return x & t; } static u64 mod, inv, r2; u64 x; }; u64 Mod64::mod, Mod64::inv, Mod64::r2; template <typename T> struct Memo { Memo(const T& g, int s, int period) : size(1 << __lg(min(s, period))), mask(size - 1), period(period), vs(size), os(size + 1) { T x(1); for (int i = 0; i < size; ++i, x *= g) os[x & mask]++; for (int i = 1; i < size; ++i) os[i] += os[i - 1]; x = 1; for (int i = 0; i < size; ++i, x *= g) vs[--os[x & mask]] = {x, i}; gpow = x; os[size] = size; } int find(T x) const { for (int t = 0; t < period; t += size, x *= gpow) { for (int m = (x & mask), i = os[m]; i < os[m + 1]; ++i) { if (x == vs[i].first) { int ret = vs[i].second - t; return ret < 0 ? ret + period : ret; } } } assert(0); } T gpow; int size, mask, period; vector< pair<T, int> > vs; vector<int> os; }; vector< pair<i64, int> > factors(i64 n) { vector< pair<i64, int> > ret; for (i64 i = 2; i128(i) * i <= n; ++i) { if (n % i == 0) { int e = 1; n /= i; while (n % i == 0) n /= i, ++e; ret.emplace_back(i, e); } } if (n > 1) ret.emplace_back(n, 1); return ret; } i64 mod_inv(i64 a, i64 mod) { i64 b = mod, s = 1, u = 0; while (b) { i64 q = a / b; swap(b, a %= b); swap(s -= q * u, u); } if (a != 1) assert(0); return s < 0 ? s + mod : s; } Mod64 msqrtp_p(Mod64 a, i64 p, int e, i64 mod) { const Mod64 one(1); i64 q = mod - 1; int s1 = 0; while (q % p == 0) q /= p, ++s1; i64 ppows[65] = {1}; for (int i = 1, m = max(e, s1); i <= m; ++i) ppows[i] = ppows[i - 1] * p; i64 pe = ppows[e], d = mod_inv(pe - q % pe, pe) * q; Mod64 r = a.pow((d + 1) / pe), t = a.pow(d); if (t == one) return r; int s2 = 1; for (Mod64 t2 = t.pow(p); t2 != one; t2 = t2.pow(p), ++s2); Mod64 c, g, u; for (Mod64 z = 2; ; z += one) { c = z.pow(q), g = c.pow(ppows[s1 - 1]); if (g != one) break; } c = c.pow(ppows[s1 - s2 - e]); Memo<Mod64> memo(g, int(sqrt(p * s2)), p); for (Mod64 u = c.pow(ppows[e]); t != one; u = u.pow(p), c = c.pow(p), --s2) { int i = memo.find(t.pow(ppows[s2 - 1])); if (i > 0) t *= u.pow(p - i), r *= c.pow(p - i); } return r; } i64 msqrtn_p(i64 a, i64 n, i64 p) { assert(n >= 1); a %= p, n %= p - 1; if (a <= 1) return a; i64 g = __gcd(p - 1, n); Mod64::set_mod(p); Mod64 ma(a), one(1); long long x = __gcd(n, (p - 1) / g); if (ma.pow((p - 1) / g) != one) { return -1; } ma = ma.pow(mod_inv(n / g, (p - 1) / g)); for (i64 div = 2; div * div * div * div <= p; ++div) { int e = 0; while (x % div == 0 && g % div == 0) { g /= div; ++e; } if (e > 0) { ma = msqrtp_p(ma, div, e, p); } } if (x > 1) { int e = 0; while (g % x == 0) { g /= x; ++e; } ma = msqrtp_p(ma, x, e, p); } if (g > 1) { ma = msqrtp_p(ma, g, 1, p); } return ma.get(); } // ----- i64 pow_mod(i64 a, i64 e, i64 mod) { i64 ret = 1; for (; e; e >>= 1, a = i128(a) * a % mod) { if (e & 1) ret = i128(ret) * a % mod; } return ret; } void verify() { for (int p = 2; p <= 500; ++p) { auto f = factors(p); if (f.size() == 1 && f[0].second == 1) { for (int k = 1; k <= p; ++k) { vector<bool> exists(p); for (int a = 0; a < p; ++a) { exists[pow_mod(a, k, p)] = true; } for (int b = 0; b < p; ++b) { int a = msqrtn_p(b, k, p); if (a < 0) assert(!exists[b]); else assert(pow_mod(a, k, p) == b); } } printf("%d: ok\n", p); } } { const i64 b = 604438754303967844; const int k = 499999273; const i64 p = 999997092002114117; i64 a = msqrtn_p(b, k, p); assert(a >= 0 && pow_mod(a, k, p) == b); } { const i64 p = 1300820172573992383; for (int k = 3; k < 100000; k *= 3) { for (int a = 1; a < 1000; ++a) { auto t = msqrtn_p(pow_mod(a, k, p), k, p); assert(pow_mod(t, k, p) == pow_mod(a, k, p)); } } } } void solve() { //verify(); int T; scanf("%d", &T); for (; T; --T) { i64 p, k, a; scanf("%lld %lld %lld", &p, &k, &a); i64 ans = msqrtn_p(a, k, p); printf("%lld\n", ans); } } int main() { clock_t beg = clock(); solve(); clock_t end = clock(); fprintf(stderr, "%.3f sec\n", double(end - beg) / CLOCKS_PER_SEC); return 0; }