結果

問題 No.981 一般冪乗根
ユーザー PachicobuePachicobue
提出日時 2020-12-30 05:34:22
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 15 ms / 6,000 ms
コード長 17,280 bytes
コンパイル時間 3,649 ms
コンパイル使用メモリ 230,040 KB
実行使用メモリ 10,624 KB
最終ジャッジ日時 2024-04-16 01:55:40
合計ジャッジ時間 50,728 ms
ジャッジサーバーID
(参考情報)
judge3 / judge4
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 5 ms
5,248 KB
testcase_01 AC 5 ms
5,376 KB
testcase_02 AC 5 ms
5,376 KB
testcase_03 AC 4 ms
5,376 KB
testcase_04 AC 5 ms
5,376 KB
testcase_05 AC 5 ms
5,376 KB
testcase_06 AC 4 ms
5,376 KB
testcase_07 AC 5 ms
5,376 KB
testcase_08 AC 5 ms
5,376 KB
testcase_09 AC 4 ms
5,376 KB
testcase_10 AC 5 ms
5,376 KB
testcase_11 AC 4 ms
5,376 KB
testcase_12 AC 4 ms
5,376 KB
testcase_13 AC 4 ms
5,376 KB
testcase_14 AC 5 ms
5,376 KB
testcase_15 AC 5 ms
5,376 KB
testcase_16 AC 4 ms
5,376 KB
testcase_17 AC 4 ms
5,376 KB
testcase_18 AC 4 ms
5,376 KB
testcase_19 AC 5 ms
5,376 KB
testcase_20 AC 5 ms
5,376 KB
testcase_21 AC 4 ms
5,376 KB
testcase_22 AC 4 ms
5,376 KB
testcase_23 AC 4 ms
5,376 KB
testcase_24 AC 4 ms
5,376 KB
testcase_25 AC 5 ms
5,376 KB
testcase_26 AC 4 ms
5,376 KB
testcase_27 AC 3 ms
5,376 KB
testcase_28 AC 15 ms
10,624 KB
evil_60bit1.txt AC 5 ms
5,376 KB
evil_60bit2.txt AC 5 ms
5,376 KB
evil_60bit3.txt AC 4 ms
5,376 KB
evil_hack AC 2 ms
5,376 KB
evil_hard_random AC 5 ms
5,376 KB
evil_hard_safeprime.txt AC 6 ms
5,376 KB
evil_hard_tonelli0 AC 8 ms
5,376 KB
evil_hard_tonelli1 AC 341 ms
20,224 KB
evil_hard_tonelli2 AC 37 ms
20,096 KB
evil_hard_tonelli3 AC 930 ms
5,376 KB
evil_sefeprime1.txt AC 4 ms
5,376 KB
evil_sefeprime2.txt AC 4 ms
5,376 KB
evil_sefeprime3.txt AC 5 ms
5,376 KB
evil_tonelli1.txt AC 508 ms
20,096 KB
evil_tonelli2.txt AC 501 ms
20,224 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
using f64 = double;
using f80 = long double;
using f128 = __float128;
using uint = unsigned int;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using LL = __int128_t;
using ULL = __uint128_t;
template<typename T> using max_heap = std::priority_queue<T>;
template<typename T> using min_heap = std::priority_queue<T, std::vector<T>, std::greater<T>>;
struct modinfo
{
    u32 mod, root, max2p;
    void set_mod(const u32 nmod) { mod = nmod; }
};
template<const modinfo& info>
class modint
{
public:
    static constexpr const u32& mod = info.mod;
    static constexpr const u32& root = info.root;
    static constexpr const u32& max2p = info.max2p;
    constexpr modint() : m_val{0} {}
    constexpr modint(const i64 v) : m_val{normll(v)} {}
    void set_raw(const uint nval) { m_val = nval; }
    constexpr u32 get() const { return m_val; }
    constexpr u32 operator()() const { return m_val; }
    constexpr modint operator-() const { return modint{0} - (*this); }
    constexpr modint& operator+=(const modint& m) { return m_val = norm(m_val + m()), *this; }
    constexpr modint& operator-=(const modint& m) { return m_val = norm(m_val + mod - m()), *this; }
    constexpr modint& operator*=(const modint& m) { return m_val = normll((i64)m_val * m() % mod), *this; }
    constexpr modint& operator/=(const modint& m) { return (*this) *= m.inv(); }
    constexpr modint operator+(const modint& m) const { return modint{*this} += m; }
    constexpr modint operator-(const modint& m) const { return modint{*this} -= m; }
    constexpr modint operator*(const modint& m) const { return modint{*this} *= m; }
    constexpr modint operator/(const modint& m) const { return modint{*this} /= m; }
    constexpr bool operator==(const modint& m) const { return m_val == m.m_val; }
    constexpr bool operator!=(const modint& m) const { return not(*this == m); }
    friend std::istream& operator>>(std::istream& is, modint& m)
    {
        i64 v;
        return is >> v, m = v, is;
    }
    friend std::ostream& operator<<(std::ostream& os, const modint& m) { return os << m.get(); }
    constexpr modint pow(u64 n) const
    {
        modint ans = 1;
        for (modint x = *this; n > 0; n >>= 1, x *= x) {
            if (n & 1ULL) { ans *= x; }
        }
        return ans;
    }
    constexpr modint inv() const { return pow(mod - 2); }
    static modint fact(const int n)
    {
        static std::vector<modint> fs{1, 1};
        for (u32 i = (u32)fs.size(); i <= (u32)n; i++) { fs.push_back(fs.back() * i); }
        return fs[n];
    }
    static modint ifact(const int n)
    {
        static std::vector<modint> ifs{1, 1};
        for (u32 i = (u32)ifs.size(); i <= (u32)n; i++) { ifs.push_back(ifs.back() * sinv(i)); }
        return ifs[n];
    }
    static modint sinv(const int n)
    {
        static std::vector<modint> is{1, 1};
        for (u32 i = (u32)is.size(); i <= (u32)n; i++) { is.push_back(-is[mod % i] * (mod / i)); }
        return is[n];
    }
    static modint comb(const int n, const int k) { return k > n or k < 0 ? modint{0} : fact(n) * ifact(n - k) * ifact(k); }
private:
    u32 m_val;
    static constexpr u32 norm(const u32 x) { return x < mod ? x : x - mod; }
    static constexpr u32 normll(const i64 x) { return norm(u32(x % mod + mod)); }
};
constexpr modinfo modinfo_1000000007 = {1000000007, 5, 1};
constexpr modinfo modinfo_998244353 = {998244353, 3, 23};
using modint_1000000007 = modint<modinfo_1000000007>;
using modint_998244353 = modint<modinfo_998244353>;
struct modinfo64
{
    u64 mod, inv, r2;
    void set_mod(const u64 nmod)
    {
        assert(nmod < (1ULL << 62)), assert(nmod & 1);
        mod = nmod, r2 = -u128{nmod} % nmod, inv = nmod;
        for (int i = 0; i < 5; i++) { inv *= 2 - nmod * inv; }
        assert(inv * mod == 1);
    }
    u64 init(const u64 w) const { return reduce((u128(w) + mod) * r2); }
    u64 reduce(const u128 x) const
    {
        const u64 y = u64(x >> 64) - u64((u128(u64(x) * inv) * mod) >> 64);
        return i64(y) < 0 ? y + mod : y;
    }
};
template<const modinfo64& info>
class modint64
{
public:
    static constexpr const u64& mod = info.mod;
    constexpr modint64() : m_val{0} {}
    constexpr modint64(const i64 v) : m_val{info.init(v)} { static_cast<void>(0); }
    modint64 operator-() const { return modint64() - (*this); }
    modint64& operator+=(const modint64& b)
    {
        if (i64(m_val += b.m_val - 2 * mod) < 0) { m_val += 2 * mod; }
        return *this;
    }
    modint64& operator-=(const modint64& b)
    {
        if (i64(m_val -= b.m_val) < 0) { m_val += 2 * mod; }
        return *this;
    }
    modint64& operator*=(const modint64& b) { return m_val = info.reduce(u128(m_val) * b.m_val), *this; }
    modint64& operator/=(const modint64& b) { return (*this) *= b.inv(); }
    modint64 operator+(const modint64& b) const { return modint64{*this} += b; }
    modint64 operator-(const modint64& b) const { return modint64{*this} -= b; }
    modint64 operator*(const modint64& b) const { return modint64{*this} *= b; }
    modint64 operator/(const modint64& b) const { return modint64{*this} /= b; }
    bool operator==(const modint64& b) const { return (m_val >= mod ? m_val - mod : m_val) == (b.m_val >= mod ? b.m_val - mod : b.m_val); }
    bool operator!=(const modint64& b) const { return not(*this == b); }
    friend std::istream& operator>>(std::istream& is, modint64& m)
    {
        i64 v;
        return is >> v, m = v, is;
    }
    friend std::ostream& operator<<(std::ostream& os, const modint64& m) { return os << m.get(); }
    constexpr modint64 pow(u128 n) const
    {
        modint64 ans = 1;
        for (modint64 x = *this; n > 0; n >>= 1, x *= x) {
            if (n & 1) { ans *= x; }
        }
        return ans;
    }
    constexpr modint64 inv() const { return pow(mod - 2); }
    constexpr u64 get() const
    {
        const u64 ans = info.reduce(m_val);
        return ans >= mod ? ans - mod : ans;
    }
    constexpr u64 operator()() const { return get(); }
private:
    u64 m_val;
};
template<typename K, typename V, int LG = 20>
class hashmap
{
public:
    hashmap() = default;
    V& operator[](const K& k)
    {
        for (uint i = hash(k);; (i += 1) &= (N - 1)) {
            if (not m_used.test(i)) {
                m_keys[i] = k, m_used.set(i);
                return m_vals[i] = V{};
            }
            if (m_keys[i] == k) { return m_vals[i]; }
        }
    }
    void erase(const K& k) const
    {
        uint i = 0;
        for (i = hash(k); m_used.test(i) and m_keys[i] != k; (i += 1) &= (N - 1)) {}
        if (m_used.test(i) and m_keys[i] == k) { m_used.reset(i); }
    }
    int count(const K& k) const
    {
        uint i = 0;
        for (i = hash(k); m_used.test(i) and m_keys[i] != k; (i += 1) &= (N - 1)) {}
        return m_used.test(i) and m_keys[i] == k;
    }
private:
    static constexpr int N = 1 << LG;
    static constexpr ull r = 11995408973635179863ULL;
    static constexpr uint hash(const ull a) { return (a * r) >> (64 - LG); }
    std::bitset<N> m_used;
    K m_keys[N];
    V m_vals[N];
};
template<typename T> constexpr T inverse(const T a, const T mod) { return a == 1 ? T{1} : ((a - inverse(mod % a, a)) * mod + 1) / a; }
template<typename T> constexpr std::pair<T, T> extgcd(const T a, const T b)
{
    if (a == 0) { return -1 / b; }
    if (b == 0) { return 1 / a; }
    const T x = inverse(a, b), y = (a * x - 1) / b;
    return {x, y};
}
template<typename T, typename V>
inline bool miller_rabin(const T& n, const std::vector<T>& as)
{
    auto pow = [&](V a, T k) -> V {
        V ans = 1;
        for (; k > 0; (a *= a) %= V{n}, k >>= 1) {
            if (k & 1) { (ans *= a) %= V{n}; }
        }
        return ans;
    };
    T d = n - 1;
    for (; (d & 1) == 0; d >>= 1) {}
    for (const T& a : as) {
        if (n <= a) { break; }
        T s = d;
        V x = pow(a, s);
        while (x != 1 and x != n - 1 and s != n - 1) {
            (x *= x) %= V(n);
            s *= 2;
        }
        if (x != n - 1 and s % 2 == 0) { return false; }
    }
    return true;
}
inline bool is_prime(const ull n)
{
    if (n % 2 == 0) { return n == 2; }
    if (n < (1ULL << 32)) {
        return miller_rabin<uint, ull>((uint)n, std::vector<uint>{2, 7, 61});
    } else {
        return miller_rabin<ull, __uint128_t>(n, std::vector<ull>{2, 325, 9375, 28178, 450775, 9780504});
    }
}
template<typename T, typename V = T>
T pollard_rho(const T n)
{
    if (n % 2 == 0) { return 2; }
    if (is_prime(n)) { return n; }
    for (T c = 1; c < n; c++) {
        if (c == n - 2) { continue; }
        auto f = [&](const T x) -> T { return T((V(x) * V(x) + V(c)) % V(n)); };
        T x = 2, y = 2, d = 1;
        while (d == 1) {
            x = f(x), y = f(f(y));
            d = std::gcd(std::max(x, y) - std::min(x, y), n);
        }
        if (d != n) { return d; }
    }
    return n;
}
std::map<ull, int> prime_factors(const ull n_)
{
    std::map<ull, int> ans;
    auto factor = [&](auto&& self, const ull n) -> void {
        if (n == 1) { return; }
        const ull p = (n < (1ULL << 32)) ? (ull)pollard_rho<uint, ull>((uint)n) : pollard_rho<ull, __uint128_t>(n);
        if (p == n) {
            ans[p]++;
            return;
        }
        self(self, p), self(self, n / p);
    };
    factor(factor, n_);
    return ans;
}
template<typename mint>
mint mod_nthroot(mint A, ull k)
{
    const ull P = mint::mod;
    if (A == 0) { return 0; }
    if (k == 0) { return A; }
    const ull g = std::gcd(P - 1, k);
    if (A.pow((P - 1) / g)() != 1) { return 0; }
    A = A.pow(inverse<ULL>(k / g, (P - 1) / g));
    if (g == 1) { return A; }
    const auto fs = prime_factors(g);
    for (const auto& [p, e] : fs) {
        ull pe = 1;
        for (int i = 0; i < e; i++) { pe *= p; }
        ull q = P - 1, Q = 0;
        while (q % p == 0) { q /= p, Q++; }
        const ull y = pe - inverse<ULL>(q, pe), z = ((ULL)y * q + 1) / (ULL)pe;
        mint X = A.pow(z);
        if ((int)Q == e) {
            A = X;
            continue;
        }
        mint Eraser = 1;
        const ull h = (P - 1) / p;
        for (mint Z = 2;; Z += 1) {
            if (Z.pow(h) != 1) {
                Eraser = Z.pow(q);
                break;
            }
        }
        mint Error = A.pow((ULL)y * q);
        mint pEraser = Eraser;
        for (ull i = 0; i < Q - 1; i++) { pEraser = pEraser.pow(p); }
        const mint ipEraser = pEraser.inv();
        hashmap<ull, ull> memo;
        {
            const ull M = std::max(1ULL, (ull)(std::sqrt(p) * std::sqrt(Q - e))), B = std::max(1ULL, ((ull)p - 1) / M);
            const mint ppEraser = pEraser.pow(B);
            mint prod = 1;
            for (ull i = 0; i < p; i += B, prod *= ppEraser) { memo[prod()] = i; }
        }
        while (Error() != 1) {
            ull l = 0;
            mint pError = Error;
            for (ull i = 0; i < Q; i++) {
                const auto npError = pError.pow(p);
                if (npError == 1) {
                    l = Q - (i + 1);
                    break;
                }
                pError = npError;
            }
            ull c = -1;
            {
                mint small = pError.inv();
                for (ull j = 0;; j++, small *= ipEraser) {
                    if (memo.count(small())) {
                        const ull i = memo[small()];
                        c = i + j;
                        break;
                    }
                }
            }
            auto pEraser2 = Eraser.pow(c);
            for (ull i = 0; i < l - e; i++) { pEraser2 = pEraser2.pow(p); }
            X *= pEraser2, Error *= pEraser2.pow(pe);
        }
        A = X;
    }
    return A;
}
class printer
{
public:
    printer()
    {
        for (int i = 0; i < 10000; i++) {
            for (int j = i, t = 3; t >= 0; t--, j /= 10) { m_dict[i * 4 + t] = (j % 10) + '0'; }
        }
    }
    ~printer() { flush(); }
    template<typename... Args> int ln(const Args&... args) { return dump(args...), put_char('\n'), 0; }
    template<typename... Args> int el(const Args&... args) { return dump(args...), put_char('\n'), flush(), 0; }
private:
    using ll = long long;
    using ull = unsigned long long;
    static constexpr ull TEN(const int d) { return d == 0 ? 1ULL : TEN(d - 1) * 10ULL; }
    void flush() { fwrite(m_memory, 1, m_tail, stdout), m_tail = 0; }
    void put_char(const char c) { m_memory[m_tail++] = c; }
    static constexpr int dn(const ull x)
    {
        return x < TEN(10)
                   ? x < TEN(5)
                         ? x < TEN(2)
                               ? x < TEN(1) ? 1 : 2
                               : x < TEN(3) ? 3 : x < TEN(4) ? 4 : 5
                         : x < TEN(7)
                               ? x < TEN(6) ? 6 : 7
                               : x < TEN(8) ? 8 : x < TEN(9) ? 9 : 10
                   : x < TEN(14)
                         ? x < TEN(12)
                               ? x < TEN(11) ? 11 : 12
                               : x < TEN(13) ? 13 : 14
                         : x < TEN(16)
                               ? x < TEN(15) ? 15 : 16
                               : x < TEN(17) ? 17 : x < TEN(18) ? 18 : 19;
    }
    template<typename T>
    void dump(T v)
    {
        if (C - m_tail < 50) { flush(); }
        if (v < 0) { put_char('-'), v = -v; }
        const auto d = dn(v);
        int i = d - 4;
        for (i = d - 4; i >= 0; i -= 4, v /= 10000) { memcpy(m_memory + m_tail + i, m_dict + (v % 10000) * 4, 4); }
        memcpy(m_memory + m_tail, m_dict + v * 4 - i, i + 4);
        m_tail += d;
    }
    template<typename T>
    void dump(const std::vector<T>& vs)
    {
        for (int i = 0; i < (int)vs.size(); i++) {
            if (i > 0) { put_char(' '); }
            dump(vs[i]);
        }
    }
    template<typename T>
    void dump(const std::vector<std::vector<T>>& vss)
    {
        for (int i = 0; i < (int)vss.size(); i++) {
            if (i > 0) { put_char('\n'); }
            dump(vss[i]);
        }
    }
    template<typename T, typename... Args> void dump(const T& v, const Args&... args) { return dump(v), put_char(' '), dump(args...), void(0); }
    static constexpr int C = 1 << 18;
    int m_tail = 0;
    char m_memory[C];
    char m_dict[10000 * 4];
} out;
class scanner
{
public:
    scanner() {}
    template<typename T>
    T val()
    {
        if (m_tail - m_head < 40) { disk_read(); }
        char c = get_char();
        const bool neg = (c == '-');
        if (neg) { c = get_char(); }
        T ans = 0;
        while (c >= '0') {
            ans = ans * T{10} + (c - '0');
            c = get_char();
        }
        return (neg ? -ans : ans);
    }
    template<typename T> T val(const T offset) { return val<T>() - offset; }
    template<typename T> std::vector<T> vec(const int n)
    {
        return make_v<T>(n, [this]() { return val<T>(); });
    }
    template<typename T> std::vector<T> vec(const int n, const T offset)
    {
        return make_v<T>(n, [this, offset]() { return val<T>(offset); });
    }
    template<typename T> std::vector<std::vector<T>> vvec(const int n0, const int n1)
    {
        return make_v<std::vector<T>>(n0, [this, n1]() { return vec<T>(n1); });
    }
    template<typename T> std::vector<std::vector<T>> vvec(const int n0, const int n1, const T offset)
    {
        return make_v<std::vector<T>>(n0, [this, n1, offset]() { return vec<T>(n1, offset); });
    }
    template<typename... Args> auto tup() { return std::tuple<std::decay_t<Args>...>{val<Args>()...}; }
    template<typename... Args> auto tup(const Args&... offsets) { return std::tuple<std::decay_t<Args>...>{val<Args>(offsets)...}; }
private:
    template<typename T, typename F>
    std::vector<T> make_v(const int n, F f)
    {
        std::vector<T> ans;
        for (int i = 0; i < n; i++) { ans.push_back(f()); }
        return ans;
    }
    char get_char() { return m_memory[m_head++]; }
    void disk_read()
    {
        std::copy(m_memory + m_head, m_memory + m_tail, m_memory);
        m_tail -= m_head, m_head = 0;
        m_tail += fread(m_memory + m_tail, 1, C - m_tail, stdin);
    }
    static constexpr int C = 1 << 18;
    int m_head = 0, m_tail = 0;
    char m_memory[C];
} in;
modinfo info;
using mint = modint<info>;
modinfo64 info64;
using mint64 = modint64<info64>;
int main()
{
    const int T = in.val<int>();
    for (int t = 0; t < T; t++) {
        const auto [P, K, A] = in.tup<ull, ull, ull>();
        if (P < (1ULL << 31)) {
            info.set_mod(P);
            const mint ans = mod_nthroot(mint{(ll)A}, K);
            if (ans.pow(K) == A) {
                out.ln(ans());
            } else {
                out.ln(-1);
            }
        } else {
            info64.set_mod(P);
            const mint64 a = A;
            static_cast<void>(0);
            const mint64 ans = mod_nthroot(a, K);
            if (ans.pow(K) == A) {
                out.ln(ans());
            } else {
                out.ln(-1);
            }
        }
    }
    return 0;
}
0