/* #region Head */ #include using namespace std; using ll = long long; using ull = unsigned long long; using ld = long double; using pll = pair; template using vc = vector; template using vvc = vc>; using vll = vc; using vvll = vvc; using vld = vc; using vvld = vvc; using vs = vc; using vvs = vvc; template using um = unordered_map; template using pq = priority_queue; template using pqa = priority_queue, greater>; template using us = unordered_set; #define REP(i, m, n) for (ll i = (m), i##_len = (ll)(n); i < i##_len; ++(i)) #define REPM(i, m, n) for (ll i = (m), i##_max = (ll)(n); i <= i##_max; ++(i)) #define REPR(i, m, n) for (ll i = (m), i##_min = (ll)(n); i >= i##_min; --(i)) #define REPD(i, m, n, d) for (ll i = (m), i##_len = (ll)(n); i < i##_len; i += (d)) #define REPMD(i, m, n, d) for (ll i = (m), i##_max = (ll)(n); i <= i##_max; i += (d)) #define REPI(itr, ds) for (auto itr = ds.begin(); itr != ds.end(); itr++) #define ALL(x) begin(x), end(x) #define SIZE(x) ((ll)(x).size()) #define PERM(c) \ sort(ALL(c)); \ for (bool c##p = 1; c##p; c##p = next_permutation(ALL(c))) #define UNIQ(v) v.erase(unique(ALL(v)), v.end()); #define CEIL(a, b) (((a) + (b)-1) / (b)) constexpr ll INF = 1'010'000'000'000'000'017LL; constexpr int IINF = 1'000'000'007LL; constexpr ll MOD = 1'000'000'007LL; // 1e9 + 7 // constexpr ll MOD = 998244353; constexpr ld EPS = 1e-12; constexpr ld PI = 3.14159265358979323846; template istream &operator>>(istream &is, vc &vec) { // vector 入力 for (T &x : vec) is >> x; return is; } template ostream &operator<<(ostream &os, vc &vec) { // vector 出力 (for dump) os << "{"; REP(i, 0, SIZE(vec)) os << vec[i] << (i == i_len - 1 ? "" : ", "); os << "}"; return os; } template ostream &operator>>(ostream &os, vc &vec) { // vector 出力 (inline) REP(i, 0, SIZE(vec)) os << vec[i] << (i == i_len - 1 ? "\n" : " "); return os; } template istream &operator>>(istream &is, pair &pair_var) { // pair 入力 is >> pair_var.first >> pair_var.second; return is; } template ostream &operator<<(ostream &os, pair &pair_var) { // pair 出力 os << "(" << pair_var.first << ", " << pair_var.second << ")"; return os; } // map, um, set, us 出力 template ostream &out_iter(ostream &os, T &map_var) { os << "{"; REPI(itr, map_var) { os << *itr; auto itrcp = itr; if (++itrcp != map_var.end()) os << ", "; } return os << "}"; } template ostream &operator<<(ostream &os, map &map_var) { return out_iter(os, map_var); } template ostream &operator<<(ostream &os, um &map_var) { os << "{"; REPI(itr, map_var) { auto [key, value] = *itr; os << "(" << key << ", " << value << ")"; auto itrcp = itr; if (++itrcp != map_var.end()) os << ", "; } os << "}"; return os; } template ostream &operator<<(ostream &os, set &set_var) { return out_iter(os, set_var); } template ostream &operator<<(ostream &os, us &set_var) { return out_iter(os, set_var); } template ostream &operator<<(ostream &os, pq &pq_var) { pq pq_cp(pq_var); os << "{"; if (!pq_cp.empty()) { os << pq_cp.top(), pq_cp.pop(); while (!pq_cp.empty()) os << ", " << pq_cp.top(), pq_cp.pop(); } return os << "}"; } void pprint() { cout << endl; } template void pprint(Head &&head, Tail &&... tail) { cout << head; if (sizeof...(Tail) > 0) cout << ' '; pprint(move(tail)...); } // dump #define DUMPOUT cerr void dump_func() { DUMPOUT << endl; } template void dump_func(Head &&head, Tail &&... tail) { DUMPOUT << head; if (sizeof...(Tail) > 0) DUMPOUT << ", "; dump_func(move(tail)...); } // chmax (更新「される」かもしれない値が前) template > bool chmax(T &xmax, const U &x, Comp comp = {}) { if (comp(xmax, x)) { xmax = x; return true; } return false; } // chmin (更新「される」かもしれない値が前) template > bool chmin(T &xmin, const U &x, Comp comp = {}) { if (comp(x, xmin)) { xmin = x; return true; } return false; } // ローカル用 #ifndef ONLINE_JUDGE #define DEBUG_ #endif #ifdef DEBUG_ #define DEB #define dump(...) \ DUMPOUT << " " << string(#__VA_ARGS__) << ": " \ << "[" << to_string(__LINE__) << ":" << __FUNCTION__ << "]" << endl \ << " ", \ dump_func(__VA_ARGS__) #else #define DEB if (false) #define dump(...) #endif #define VAR(type, ...) \ type __VA_ARGS__; \ cin >> __VA_ARGS__; template istream &operator,(istream &is, T &rhs) { return is >> rhs; } template ostream &operator,(ostream &os, const T &rhs) { return os << ' ' << rhs; } struct AtCoderInitialize { static constexpr int IOS_PREC = 15; static constexpr bool AUTOFLUSH = false; AtCoderInitialize() { ios_base::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); cout << fixed << setprecision(IOS_PREC); if (AUTOFLUSH) cout << unitbuf; } } ATCODER_INITIALIZE; void Yn(bool p) { cout << (p ? "Yes" : "No") << endl; } void YN(bool p) { cout << (p ? "YES" : "NO") << endl; } /* #endregion */ // #include // using namespace atcoder; /* #region kth_root */ // 以下から拝借 // Submitted https://judge.yosupo.jp/submission/23481 namespace inner { using i32 = int32_t; using u32 = uint32_t; using i64 = int64_t; using u64 = uint64_t; template T gcd(T a, T b) { while (b) swap(a %= b, b); return a; } template T inv(T a, T p) { T b = p, x = 1, y = 0; while (a) { T q = b / a; swap(a, b %= a); swap(x, y -= q * x); } assert(b == 1); return y < 0 ? y + p : y; } template T modpow(T a, U n, T p) { T ret = 1 % p; for (; n; n >>= 1, a = U(a) * a % p) if (n & 1) ret = U(ret) * a % p; return ret; } } // namespace inner using namespace std; struct ArbitraryLazyMontgomeryModInt { using mint = ArbitraryLazyMontgomeryModInt; using i32 = int32_t; using u32 = uint32_t; using u64 = uint64_t; static u32 mod; static u32 r; static u32 n2; static u32 get_r() { u32 ret = mod; for (i32 i = 0; i < 4; ++i) ret *= 2 - mod * ret; return ret; } static void set_mod(u32 m) { assert(m < (1 << 30)); assert((m & 1) == 1); mod = m; n2 = -u64(m) % m; r = get_r(); assert(r * mod == 1); } u32 a; ArbitraryLazyMontgomeryModInt() : a(0) {} ArbitraryLazyMontgomeryModInt(const int64_t &b) : a(reduce(u64(b % mod + mod) * n2)){}; static u32 reduce(const u64 &b) { return (b + u64(u32(b) * u32(-r)) * mod) >> 32; } mint &operator+=(const mint &b) { if (i32(a += b.a - 2 * mod) < 0) a += 2 * mod; return *this; } mint &operator-=(const mint &b) { if (i32(a -= b.a) < 0) a += 2 * mod; return *this; } mint &operator*=(const mint &b) { a = reduce(u64(a) * b.a); return *this; } mint &operator/=(const mint &b) { *this *= b.inverse(); return *this; } mint operator+(const mint &b) const { return mint(*this) += b; } mint operator-(const mint &b) const { return mint(*this) -= b; } mint operator*(const mint &b) const { return mint(*this) *= b; } mint operator/(const mint &b) const { return mint(*this) /= b; } bool operator==(const mint &b) const { return (a >= mod ? a - mod : a) == (b.a >= mod ? b.a - mod : b.a); } bool operator!=(const mint &b) const { return (a >= mod ? a - mod : a) != (b.a >= mod ? b.a - mod : b.a); } mint operator-() const { return mint() - mint(*this); } mint pow(u64 n) const { mint ret(1), mul(*this); while (n > 0) { if (n & 1) ret *= mul; mul *= mul; n >>= 1; } return ret; } friend ostream &operator<<(ostream &os, const mint &b) { return os << b.get(); } friend istream &operator>>(istream &is, mint &b) { int64_t t; is >> t; b = ArbitraryLazyMontgomeryModInt(t); return (is); } mint inverse() const { return pow(mod - 2); } u32 get() const { u32 ret = reduce(a); return ret >= mod ? ret - mod : ret; } static u32 get_mod() { return mod; } }; typename ArbitraryLazyMontgomeryModInt::u32 ArbitraryLazyMontgomeryModInt::mod; typename ArbitraryLazyMontgomeryModInt::u32 ArbitraryLazyMontgomeryModInt::r; typename ArbitraryLazyMontgomeryModInt::u32 ArbitraryLazyMontgomeryModInt::n2; struct montgomery64 { using mint = montgomery64; using i64 = int64_t; using u64 = uint64_t; using u128 = __uint128_t; static u64 mod; static u64 r; static u64 n2; static u64 get_r() { u64 ret = mod; for (i64 i = 0; i < 5; ++i) ret *= 2 - mod * ret; return ret; } static void set_mod(u64 m) { assert(m < (1LL << 62)); assert((m & 1) == 1); mod = m; n2 = -u128(m) % m; r = get_r(); assert(r * mod == 1); } u64 a; montgomery64() : a(0) {} montgomery64(const int64_t &b) : a(reduce((u128(b) + mod) * n2)){}; static u64 reduce(const u128 &b) { return (b + u128(u64(b) * u64(-r)) * mod) >> 64; } mint &operator+=(const mint &b) { if (i64(a += b.a - 2 * mod) < 0) a += 2 * mod; return *this; } mint &operator-=(const mint &b) { if (i64(a -= b.a) < 0) a += 2 * mod; return *this; } mint &operator*=(const mint &b) { a = reduce(u128(a) * b.a); return *this; } mint &operator/=(const mint &b) { *this *= b.inverse(); return *this; } mint operator+(const mint &b) const { return mint(*this) += b; } mint operator-(const mint &b) const { return mint(*this) -= b; } mint operator*(const mint &b) const { return mint(*this) *= b; } mint operator/(const mint &b) const { return mint(*this) /= b; } bool operator==(const mint &b) const { return (a >= mod ? a - mod : a) == (b.a >= mod ? b.a - mod : b.a); } bool operator!=(const mint &b) const { return (a >= mod ? a - mod : a) != (b.a >= mod ? b.a - mod : b.a); } mint operator-() const { return mint() - mint(*this); } mint pow(u128 n) const { mint ret(1), mul(*this); while (n > 0) { if (n & 1) ret *= mul; mul *= mul; n >>= 1; } return ret; } friend ostream &operator<<(ostream &os, const mint &b) { return os << b.get(); } friend istream &operator>>(istream &is, mint &b) { int64_t t; is >> t; b = montgomery64(t); return (is); } mint inverse() const { return pow(mod - 2); } u64 get() const { u64 ret = reduce(a); return ret >= mod ? ret - mod : ret; } static u64 get_mod() { return mod; } }; typename montgomery64::u64 montgomery64::mod, montgomery64::r, montgomery64::n2; unsigned long long rng() { static unsigned long long x_ = 88172645463325252ULL; x_ = x_ ^ (x_ << 7); return x_ = x_ ^ (x_ >> 9); } namespace fast_factorize { using u64 = uint64_t; template bool miller_rabin(u64 n, vector as) { if (mint::get_mod() != n) mint::set_mod(n); u64 d = n - 1; while (~d & 1) d >>= 1; mint e{1}, rev{int64_t(n - 1)}; for (u64 a : as) { if (n <= a) break; u64 t = d; mint y = mint(a).pow(t); while (t != n - 1 && y != e && y != rev) { y *= y; t *= 2; } if (y != rev && t % 2 == 0) return false; } return true; } bool is_prime(u64 n) { if (~n & 1) return n == 2; if (n <= 1) return false; if (n < (1LL << 30)) return miller_rabin(n, {2, 7, 61}); else return miller_rabin(n, {2, 325, 9375, 28178, 450775, 9780504, 1795265022}); } template T pollard_rho(T n) { if (~n & 1) return 2; if (is_prime(n)) return n; if (mint::get_mod() != n) mint::set_mod(n); mint R, one = 1; auto f = [&](mint x) { return x * x + R; }; auto rnd = [&]() { return rng() % (n - 2) + 2; }; while (1) { mint x, y, ys, q = one; R = rnd(), y = rnd(); T g = 1; constexpr int m = 128; for (int r = 1; g == 1; r <<= 1) { x = y; for (int i = 0; i < r; ++i) y = f(y); for (int k = 0; g == 1 && k < r; k += m) { ys = y; for (int i = 0; i < m && i < r - k; ++i) q *= x - (y = f(y)); g = inner::gcd(q.get(), n); } } if (g == n) do g = inner::gcd((x - (ys = f(ys))).get(), n); while (g == 1); if (g != n) return g; } exit(1); } vector inner_factorize(u64 n) { if (n <= 1) return {}; u64 p; if (n <= (1LL << 30)) p = pollard_rho(n); else p = pollard_rho(n); if (p == n) return {p}; auto l = inner_factorize(p); auto r = inner_factorize(n / p); copy(begin(r), end(r), back_inserter(l)); return l; } vector factorize(u64 n) { auto ret = inner_factorize(n); sort(begin(ret), end(ret)); return ret; } } // namespace fast_factorize using fast_factorize::factorize; using fast_factorize::is_prime; /** * @brief 高速素因数分解(Miller Rabin/Pollard's Rho) * @docs docs/prime/fast-factorize.md */ namespace kth_root_mod { // fast BS-GS template 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.get() & 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.get() & 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.get() & 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> vs; vector os; }; using inner::gcd; using inner::inv; using inner::modpow; template mint pe_root(INT c, INT pi, INT ei, INT p) { if (mint::get_mod() != decltype(mint::a)(p)) mint::set_mod(p); INT s = p - 1, t = 0; while (s % pi == 0) s /= pi, ++t; INT pe = 1; for (INT _ = 0; _ < ei; ++_) pe *= pi; INT u = inv(pe - s % pe, pe); mint mc = c, one = 1; mint z = mc.pow((s * u + 1) / pe); mint zpe = mc.pow(s * u); if (zpe == one) return z; assert(t > ei); mint vs; { INT ptm1 = 1; for (INT _ = 0; _ < t - 1; ++_) ptm1 *= pi; for (mint v = 2;; v += one) { vs = v.pow(s); if (vs.pow(ptm1) != one) break; } } mint vspe = vs.pow(pe); INT vs_e = ei; mint base = vspe; for (INT _ = 0; _ < t - ei - 1; _++) base = base.pow(pi); Memo memo(base, (INT)(sqrt(t - ei) * sqrt(pi)) + 1, pi); while (zpe != one) { mint tmp = zpe; INT td = 0; while (tmp != 1) ++td, tmp = tmp.pow(pi); INT e = t - td; while (vs_e != e) { vs = vs.pow(pi); vspe = vspe.pow(pi); ++vs_e; } // BS-GS ... find (zpe * ( vspe ^ n ) ) ^( p_i ^ (td - 1) ) = 1 mint base_zpe = zpe.inverse(); for (INT _ = 0; _ < td - 1; _++) base_zpe = base_zpe.pow(pi); INT bsgs = memo.find(base_zpe); z *= vs.pow(bsgs); zpe *= vspe.pow(bsgs); } return z; } template INT inner_kth_root(INT a, INT k, INT p) { a %= p; if (k == 0) return a == 1 ? a : -1; if (a <= 1 || k <= 1) return a; assert(p > 2); if (mint::get_mod() != decltype(mint::a)(p)) mint::set_mod(p); INT g = gcd(p - 1, k); if (modpow(a, (p - 1) / g, p) != 1) return -1; a = mint(a).pow(inv(k / g, (p - 1) / g)).get(); unordered_map fac; for (auto &f : factorize(g)) fac[f]++; if (mint::get_mod() != decltype(mint::a)(p)) mint::set_mod(p); for (auto pp : fac) a = pe_root(a, pp.first, pp.second, p).get(); return a; } int64_t kth_root(int64_t a, int64_t k, int64_t p) { if (max({a, k, p}) < (1LL << 30)) return inner_kth_root(a, k, p); else return inner_kth_root(a, k, p); } } // namespace kth_root_mod using kth_root_mod::kth_root; /* #endregion */ // Problem void solve() { VAR(int, t); REP(i, 0, t) { VAR(ll, x, k); pprint(kth_root(x, k, MOD)); } } // entry point int main() { solve(); return 0; }