結果
問題 |
No.3250 最小公倍数
|
ユーザー |
![]() |
提出日時 | 2025-08-29 22:53:32 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
TLE
|
実行時間 | - |
コード長 | 18,856 bytes |
コンパイル時間 | 2,432 ms |
コンパイル使用メモリ | 195,352 KB |
実行使用メモリ | 177,952 KB |
最終ジャッジ日時 | 2025-08-29 22:53:55 |
合計ジャッジ時間 | 21,151 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 1 |
other | AC * 18 TLE * 3 |
ソースコード
#include <algorithm> #include <array> #include <bit> #include <cassert> #include <cmath> #include <cstddef> #include <cstdint> #include <cstdlib> #include <deque> #include <functional> #include <iomanip> #include <iostream> #include <iterator> #include <limits> #include <map> #include <numeric> #include <optional> #include <queue> #include <random> #include <ranges> #include <set> #include <sstream> #include <stdexcept> #include <string> #include <tuple> #include <type_traits> #include <utility> #include <vector> struct IOSetup { IOSetup() { std::cin.tie(nullptr); std::ios::sync_with_stdio(false); std::cout << std::fixed << std::setprecision(15); std::cerr << std::fixed << std::setprecision(8); } }; IOSetup iosetup; using ll = int64_t; using int128_t = __int128; using uint128_t = unsigned __int128; template <typename T> constexpr auto rep_iota_impl(T start, T stop) noexcept { return std::views::iota(start, (start < stop ? stop : start)); } template <typename T = int64_t> inline constexpr auto rep_impl(auto start, auto stop) noexcept { return rep_iota_impl<T>(start, stop); } template <typename T = int64_t> inline constexpr auto rep_impl(auto stop) noexcept { return rep_iota_impl<T>(0, stop); } template <class... Ts> inline void read(Ts&... ts) { (std::cin >> ... >> ts); } template <typename T = int64_t> std::vector<T> VEC(int size) { std::vector<T> res(size); for (T& x : res) std::cin >> x; return res; } template <class Iterable> auto max(const Iterable& A) { if (A.empty()) { assert(false); } return *std::max_element(A.begin(), A.end()); } template <typename T, typename T2> auto max(T a, T2 b) -> std::common_type_t<T, T2> { return (a < b) ? b : a; } using std::vector; template <typename T> void cumsum_inplace(vector<T>& A) { for (const auto i : rep_impl(A.size() - 1)) A[i + 1] = A[i] + A[i + 1]; } template <typename T> vector<T> cumsum(vector<T> A, auto initial) { A.insert(A.begin(), static_cast<T>(initial)); cumsum_inplace(A); return A; } template <typename T = int64_t> inline constexpr std::pair<T, T> inv_gcd(T a, T base) { static_assert(std::is_signed<T>::value); assert(base != 0); if (base < 0) base = -(base); if ((a %= base) < 0) a += base; if (a == 0) return {base, 0}; T s = base, t = a; T m0 = 0, m1 = 1; while (t) { const T u = s / t; s -= t * u; m0 -= m1 * u; std::swap(s, t); std::swap(m0, m1); } if (m0 < 0) m0 += base / s; return {s, m0}; } template <typename T, typename UInt> inline constexpr UInt safe_mod_uint(const T x, const UInt d) { static_assert(std::is_integral_v<T>); static_assert(std::is_integral_v<UInt> && std::is_unsigned_v<UInt>); assert(d != 0); if constexpr (std::is_signed_v<T>) { if (x >= 0) { return static_cast<UInt>(x % d); } else { using T2 = std::make_unsigned_t<T>; T2 abs = T2(0) - static_cast<T2>(x); abs %= d; return (abs != 0) ? static_cast<UInt>(d - abs) : 0; } } else if constexpr (std::is_unsigned_v<T>) { return static_cast<UInt>(x % d); } else { static_assert([]() -> bool { return false; }()); } } template <typename U1, typename U2> inline constexpr U1 pow_mod_constexpr(U1 base, auto exp, const U1 mod) { assert(mod != 0); assert(0 <= exp); if (mod == 1) return 0; if (not(base < mod)) base %= mod; assert(0 <= base && base < mod); U1 res = 1; while (exp) { if (exp & 1) res = static_cast<U2>(res) * base % mod; base = static_cast<U2>(base) * base % mod; exp >>= 1; } return res; } inline constexpr uint32_t pow_mod_uint32(auto base, int64_t exp, uint32_t mod) { assert(0 <= exp); assert(mod != 0); return pow_mod_constexpr<uint32_t, uint64_t>(safe_mod_uint(base, mod), exp, mod); } inline uint64_t pow_mod_uint64(auto base, int64_t exp, uint64_t mod) { using uint128_t = unsigned __int128; assert(0 <= exp); assert(mod != 0); return pow_mod_constexpr<uint64_t, uint128_t>(safe_mod_uint(base, mod), exp, mod); } template <typename T> void put(const T& t) { std::cout << t; } template <typename... Ts> void print(const Ts&... ts) { put(ts...); std::cout << "\n"; } using std::cin; using std::cout; using std::map; using std::pair; using std::set; using std::string; using std::tuple; using std::vector; inline pair<vector<int64_t>, vector<int64_t>> lpf_table(int64_t N) { using ll = int64_t; if (N <= 1) { N = 1; } vector<ll> dp(N + 1, 0); vector<ll> P; for (const auto x : rep_impl(2, N + 1)) { if (dp[x] == 0) { dp[x] = x; P.push_back(x); } const ll lpf = dp[x]; for (ll np : P) { if (lpf < np || !(np * x <= N)) { break; } dp[np * x] = np; } } return {dp, P}; } using ll = int64_t; inline pair<vector<ll>, vector<ll>> lpf_exp_pow(const vector<ll>& lpf) { if (lpf.size() <= 1) return {vector<ll>{0, 0}, vector<ll>{0, 0}}; const ll N = lpf.size() - 1; vector<ll> exp(N + 1, 1); vector<ll> pow(lpf); exp[0] = exp[1] = 0; pow[0] = pow[1] = 0; for (const auto x : rep_impl(2, N + 1)) { const ll p = lpf[x]; const ll y = x / p; if (y % p == 0) { exp[x] = exp[y] + 1; pow[x] = pow[y] * p; } } return {exp, pow}; } using std::pair; using std::vector; struct LinearSieve { using ll = int64_t; ll N; vector<ll> _lpf, P; vector<ll> lpf_exp, lpf_pow; public: explicit LinearSieve(ll N_) { N = max(0, N_) + 1000; std::tie(_lpf, P) = lpf_table(N); std::tie(lpf_exp, lpf_pow) = lpf_exp_pow(_lpf); } ll lpf(ll X) const { assert(1 <= X && X <= N); return _lpf[X]; } vector<pair<ll, ll>> factors(ll X) const { assert(1 <= X && X <= N); vector<pair<ll, ll>> F; while (2 <= X) { ll p = lpf(X); ll e = lpf_exp[X]; ll pow = lpf_pow[X]; X /= pow; F.push_back({p, e}); } return F; } }; using std::pair; using std::vector; template <typename T> struct CSR { using ll = int64_t; ll N = 0; vector<ll> start{}; vector<ll> I; vector<T> E; bool frozen = false; CSR() = default; explicit CSR(ll N) : N(N), start(N + 1) {} explicit CSR(ll N, vector<pair<ll, T>> IE) : N(N) { for (auto [i, t] : IE) { I.push_back(i); E.push_back(t); } build(); } void reset(ll N) { this->N = N; start.resize(N + 1); I.clear(); E.clear(); frozen = false; } void clear() { reset(0); } void push_back(ll i, T t) { assert(!frozen); assert(0 <= i && i < N); I.push_back(i); E.push_back(t); } void build() { assert(!frozen); const ll M = E.size(); vector<ll> C(N); vector<T> nE(M); for (const auto j : rep_impl(M)) { assert(0 <= I[j] && I[j] < N); C[I[j]] += 1; } start = cumsum(C, 0); auto it = start; for (const auto j : rep_impl(M)) { ll i = I[j]; nE[it[i]] = E[j]; it[i] += 1; } std::swap(E, nE); I.clear(); frozen = true; } auto operator[](int64_t idx) const { assert(frozen); assert(0 <= idx && idx < N); return std::ranges::subrange(E.begin() + start[idx], E.begin() + start[idx + 1]); } auto operator[](int64_t idx) { assert(frozen); assert(0 <= idx && idx < N); return std::ranges::subrange(E.begin() + start[idx], E.begin() + start[idx + 1]); } using subrange = std::ranges::subrange<typename vector<T>::iterator>; subrange at(int64_t idx) { assert(frozen); assert(0 <= idx && idx < N); return std::ranges::subrange(E.begin() + start[idx], E.begin() + start[idx + 1]); } ll size() const { return N; } ll num_edges() const { return E.size(); } template <typename U> static CSR<U> from_vector(const vector<vector<U>>& G) { CSR<U> res; res.N = G.size(); for (const auto i : rep_impl(res.N)) { for (auto e : G[i]) { res.push_back(i, e); } } res.build(); return res; } vector<vector<T>> to_vector() const { vector<vector<T>> res(N); for (const auto i : rep_impl(N)) { for (auto e : at(i)) { res[i].push_back(e); } } return res; } }; template <bool weighted = false, typename Weight = int64_t> struct Tree { using ll = int64_t; constexpr static ll NIL = -1e9; ll N = NIL; ll M = 0; ll root = NIL; CSR<pair<ll, Weight>> G_weighted; CSR<pair<ll, Weight>> T_weighted; CSR<ll> T; vector<ll> pi; vector<Weight> pi_edge_cost; vector<ll> depth; vector<Weight> depth_weighted; vector<ll> root_to_leaf; vector<ll> subtree_size; vector<ll> called_at; vector<ll> index; vector<ll> edge_tour; vector<ll> head; bool frozen = false; private: void resize_fields(ll N) { pi.assign(N, NIL); pi_edge_cost.assign(N, Weight{}); depth.assign(N, NIL); depth_weighted.assign(N, NIL); root_to_leaf.clear(); root_to_leaf.reserve(N); subtree_size.assign(N, 1); called_at.assign(N, NIL); index.assign(N, NIL); edge_tour.clear(); edge_tour.reserve(2 * N); head.assign(N, NIL); } public: Tree(ll N, ll root = NIL) : N(N), M(0), root(root), G_weighted(N) { if (N == 1) { root = 0; build(); } } void add_undirected_edge(ll frm, ll to) { static_assert(not weighted); add_undirected_edge(frm, to, Weight{1}); } void add_undirected_edge(ll frm, ll to, Weight cost) { assert(!frozen); G_weighted.push_back(frm, {to, cost}); G_weighted.push_back(to, {frm, cost}); M += 1; if (0 < N && M == N - 1 && 0 <= root && root < N) { build(); } } void reset(ll N) { this->N = N; M = 0; root = NIL; frozen = false; } void build() { if (frozen) return; assert(!frozen); assert(N != NIL); assert(N != 0 && M == N - 1); assert(0 <= root && root < N); assert(G_weighted.size() == N); G_weighted.build(); T_weighted.reset(N); T.reset(N); resize_fields(N); depth[root] = 0; dfs(root, NIL); T_weighted.build(); T.build(); head[root] = root; hld(root, NIL); G_weighted.clear(); frozen = true; } void dfs(ll v, ll p) { for (auto [a, cost] : G_weighted[v]) { if (a == p) continue; T_weighted.push_back(v, {a, cost}); T.push_back(v, a); depth[a] = depth[v] + 1; depth_weighted[a] = depth_weighted[v] + cost; pi[a] = v; pi_edge_cost[a] = cost; dfs(a, v); subtree_size[v] += subtree_size[a]; } } auto iter_subtree(ll v) { ll start = index[v]; ll end = start + subtree_size[v]; return std::ranges::subrange(root_to_leaf.begin() + start, root_to_leaf.begin() + end); } void hld(ll v, ll p) { index[v] = root_to_leaf.size(); called_at[v] = edge_tour.size(); edge_tour.push_back(v); root_to_leaf.push_back(v); ll maxsize = 0; ll eldest = NIL; ll argmax = NIL; for (const auto j : rep_impl(T[v].size())) { ll a = T[v][j]; assert(a != p); if (maxsize < subtree_size[a]) { maxsize = subtree_size[a]; eldest = a; argmax = j; } } if (eldest != NIL) { std::swap(T_weighted.at(v)[0], T_weighted.at(v)[argmax]); std::swap(T.at(v)[0], T.at(v)[argmax]); head[eldest] = head[v]; hld(eldest, v); } for (const auto i : rep_impl(1, T[v].size())) { auto a = T[v][i]; head[a] = a; hld(a, v); } edge_tour.push_back(~v); } auto operator[](ll v) { if constexpr (weighted) { return T_weighted[v]; } return T[v]; } auto adj(ll v) { return T[v]; } ll size() const { return N; } }; constexpr int64_t MOD = 998'244'353; constexpr bool is_prime32_constexpr(uint32_t n) { if (n <= 1) return false; if (n == 2 || n == 7 || n == 61) return true; if (n % 2 == 0) return false; uint32_t d = n - 1; while (d % 2 == 0) d /= 2; constexpr uint32_t bases[3] = {2, 7, 61}; for (uint32_t a : bases) { uint32_t t = d; uint32_t y = pow_mod_constexpr<uint32_t, uint64_t>(a, t, n); while (t != n - 1 && y != 1 && y != n - 1) { y = y * y % n; t <<= 1; } if (y != n - 1 && t % 2 == 0) { return false; } } return true; } static_assert(is_prime32_constexpr(2)); template <int64_t MOD_> struct static_modint { static_assert(1 <= MOD_); static_assert(MOD_ < (uint32_t{1} << 31)); static constexpr int32_t MOD = int32_t{MOD_}; static constexpr uint32_t UMOD = uint32_t{MOD}; static_assert(std::in_range<int32_t>(MOD_)); static_assert(std::in_range<int32_t>(MOD)); static_assert(std::in_range<int32_t>(UMOD)); using mint = static_modint; uint32_t _v = 0; private: static constexpr bool is_prime = is_prime32_constexpr(UMOD); static constexpr uint32_t inv_uint32(uint32_t x) { assert(x != 0); if constexpr (is_prime) { return pow_mod_uint32(x, UMOD - 2, UMOD); } else { auto [g, inv] = inv_gcd<int32_t>(x, UMOD); assert(g == 1); return inv; } } public: static constexpr mint raw(uint32_t v) noexcept { mint a; a._v = v; return a; } constexpr static_modint() : _v(0) {} constexpr static_modint(int32_t v) : _v((v %= MOD) < 0 ? v + MOD : v) {} constexpr static_modint(int64_t v) : _v((v %= MOD) < 0 ? v + MOD : v) {} constexpr static_modint(uint32_t v) : _v(v % UMOD) {} constexpr static_modint(uint64_t v) : _v(v % UMOD) {} static constexpr int32_t mod() { return MOD; } static constexpr int32_t get_mod() { return mod(); } constexpr int32_t val() const { return _v; } constexpr mint& operator+=(mint rhs) { if (_v >= UMOD - rhs._v) _v -= UMOD; _v += rhs._v; return *this; } constexpr mint& operator-=(mint rhs) { if (_v < rhs._v) _v += UMOD; _v -= rhs._v; return *this; } constexpr mint& operator*=(mint rhs) { _v = (uint64_t)_v * rhs._v % UMOD; return *this; } constexpr mint& operator/=(mint rhs) { _v = (uint64_t)_v * inv_uint32(rhs._v) % UMOD; return *this; } constexpr mint operator+() const { return *this; } constexpr mint operator-() const { if (_v == 0) return *this; return mint::raw(UMOD - _v); } friend constexpr mint operator+(mint lhs, mint rhs) { return lhs += rhs; } friend constexpr mint operator-(mint lhs, mint rhs) { return lhs -= rhs; } friend constexpr mint operator*(mint lhs, mint rhs) { return lhs *= rhs; } friend constexpr mint operator/(mint lhs, mint rhs) { return lhs /= rhs; } friend constexpr bool operator<(mint lhs, mint rhs) { return lhs._v < rhs._v; } friend constexpr bool operator==(mint lhs, mint rhs) { return lhs._v == rhs._v; } friend constexpr bool operator!=(mint lhs, mint rhs) { return lhs._v != rhs._v; } constexpr mint inv() const { assert(_v != 0); return mint::raw(inv_uint32(_v)); } constexpr mint pow(const int64_t exp) const { if (exp < 0) { return mint::raw(pow_mod_uint32(inv_uint32(_v), -exp, UMOD)); } return mint::raw(pow_mod_uint32(_v, exp, UMOD)); } struct ntt_info_t { int rank2; int omega; }; static constexpr ntt_info_t ntt_info() { if (UMOD == 167772161) return {25, 17}; if (UMOD == 469762049) return {26, 30}; if (UMOD == 754974721) return {24, 362}; if (UMOD == 998244353) return {23, 31}; return {-1, -1}; } static constexpr bool ntt_friendly = (ntt_info().rank2 != -1); friend std::ostream& operator<<(std::ostream& os, const mint& x) { return os << x.val(); } friend std::istream& operator>>(std::istream& is, mint& x) { int64_t v; is >> v; x = mint(v); return is; } }; using mint = static_modint<MOD>; int main() { int64_t N; read(N); auto A = VEC(N); ll U = max(A); vector<pair<ll, ll>> E; auto T = Tree<0>(N, 0); for ([[maybe_unused]] const auto _i : rep_impl(N - 1)) { int64_t a, b; read(a, b); a -= 1, b -= 1; T.add_undirected_edge(a, b); } T.build(); vector<ll> res(N); vector<ll> C(U + 1, 0); vector<ll> ord(U + 1, 0); auto ls = LinearSieve(U); mint lcm = 1; auto push = [&](ll x) { if (C[x] == 0) { for (auto [p, e] : ls.factors(x)) { if (ord[p] < e) { lcm *= mint(p).pow(e - ord[p]); ord[p] = e; } } } C[x] += 1; }; auto del = [&](ll x) { C[x] -= 1; if (C[x] == 0) { for (auto [p, e] : ls.factors(x)) { ord[p] = 0; } } }; auto dfs = [&](auto&& dfs, ll x, bool keep) -> void { ll eldest = -1; if (T[x].size()) { eldest = T[x][0]; } for (auto a : T[x]) { if (a != eldest) { dfs(dfs, a, 0); } } if (eldest != -1) { dfs(dfs, eldest, 1); } for (auto a : T[x]) { if (a != eldest) { for (auto b : T.iter_subtree(a)) { push(A[b]); } } } push(A[x]); res[x] = lcm.val(); if (!keep) { for (auto a : T.iter_subtree(x)) { del(A[a]); } lcm = 1; } return; }; dfs(dfs, 0, 1); for (auto a : res) { print(a); } }