結果
問題 | No.2360 Path to Integer |
ユーザー | cutmdo |
提出日時 | 2024-12-19 23:41:01 |
言語 | C++23 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 270 ms / 2,500 ms |
コード長 | 11,734 bytes |
コンパイル時間 | 2,604 ms |
コンパイル使用メモリ | 166,052 KB |
実行使用メモリ | 102,284 KB |
最終ジャッジ日時 | 2024-12-19 23:41:09 |
合計ジャッジ時間 | 6,507 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 45 ms
49,944 KB |
testcase_01 | AC | 45 ms
50,084 KB |
testcase_02 | AC | 44 ms
49,944 KB |
testcase_03 | AC | 45 ms
50,136 KB |
testcase_04 | AC | 45 ms
50,056 KB |
testcase_05 | AC | 45 ms
50,096 KB |
testcase_06 | AC | 45 ms
50,072 KB |
testcase_07 | AC | 46 ms
50,588 KB |
testcase_08 | AC | 63 ms
55,100 KB |
testcase_09 | AC | 270 ms
99,664 KB |
testcase_10 | AC | 250 ms
102,284 KB |
testcase_11 | AC | 247 ms
101,608 KB |
testcase_12 | AC | 186 ms
100,912 KB |
testcase_13 | AC | 266 ms
99,528 KB |
testcase_14 | AC | 244 ms
98,480 KB |
testcase_15 | AC | 260 ms
99,396 KB |
testcase_16 | AC | 245 ms
98,352 KB |
ソースコード
#include <vector> #define PROBLEM "https://yukicoder.me/problems/no/2360" #include <iostream> #include <queue> #include <unordered_map> #include <ranges> #include <tuple> #include <vector> #include <iterator> #include <iostream> #include <deque> namespace mtd { template <class S, S element, class op > requires std::is_invocable_r_v<S, op, S, S> struct Monoid { using value_type = S; constexpr static S _element = element; using op_type = op; S m_val; constexpr Monoid(S val) : m_val(val) {} constexpr Monoid() : Monoid(element) {} constexpr Monoid binaryOperation(const Monoid& m2) const { return op()(m_val, m2.m_val); } friend std::ostream& operator<<(std::ostream& os, const Monoid<S, element, op>& m) { return os << m.m_val; } }; namespace __detail { template <typename T, template <typename, auto, typename> typename S> concept is_specialization_of = requires { typename std::enable_if_t<std::is_same_v< T, S<typename T::value_type, T::_element, typename T::op_type>>>; }; } template <typename M> concept monoid = __detail::is_specialization_of<M, Monoid>;} namespace mtd { template <class Node = int, class Cost = long long> class Graph { using Edge = std::pair<Node, Cost>; using Edges = std::vector<Edge>; const int m_n; std::vector<Edges> m_graph; public: Graph(int n) : m_n(n), m_graph(n) {} Graph(const std::vector<Edges>& edges) : m_n(edges.size()), m_graph(edges) {} auto addEdge(const Node& f, const Node& t, const Cost& c = 1) { m_graph[f].emplace_back(t, c); } auto addEdgeUndirected(const Node& f, const Node& t, const Cost& c = 1) { addEdge(f, t, c); addEdge(t, f, c); } auto getEdges(const Node& from) const { class EdgesRange { const typename Edges::const_iterator b, e; public: EdgesRange(const Edges& edges) : b(edges.begin()), e(edges.end()) {} auto begin() const { return b; } auto end() const { return e; } }; return EdgesRange(m_graph[from]); } auto getEdges() const { std::deque<std::tuple<Node, Node, Cost>> edges; for (Node from : std::views::iota(0, m_n)) { for (const auto& [to, c] : getEdges(from)) { edges.emplace_back(from, to, c); } } return edges; } auto getEdgesExcludeCost() const { std::deque<std::pair<Node, Node>> edges; for (Node from : std::views::iota(0, m_n)) { for (const auto& [to, _] : getEdges(from)) { edges.emplace_back(from, to); } } return edges; } auto reverse() const { auto rev = Graph<Node, Cost>(m_n); for (const auto& [from, to, c] : getEdges()) { rev.addEdge(to, from, c); } return rev; } auto size() const { return m_n; }; auto debug(bool directed = false) const { for (const auto& [f, t, c] : getEdges()) { if (f < t || directed) { std::cout << f << " -> " << t << ": " << c << std::endl; } } } };} namespace mtd { template <class T> class Math { const std::vector<T> m_fac; const std::vector<T> m_finv; auto constructFac(int s) { std::vector<T> fac(s); fac[0] = fac[1] = 1; for (long long i = 2; i < s; ++i) { fac[i] = fac[i - 1] * i; } return fac; } auto constructInv(int s) { std::vector<T> finv(s); finv[s - 1] = 1 / m_fac[s - 1]; for (long long i = s - 2; i >= 0; --i) { finv[i] = finv[i + 1] * (i + 1); } return finv; } public: constexpr Math(long long size = 3 * 1e6) : m_fac(constructFac(size)), m_finv(constructInv(size)) {} static constexpr T pow(T a, long long b) { T ans = 1; while (b > 0) { if (b & 1) { ans *= a; } b >>= 1; a *= a; } return ans; } constexpr auto fact(int n) const { return (n < 0) ? 0 : m_fac[n]; } constexpr auto factInv(int n) const { return (n < 0 ? 0 : m_finv[n]); } constexpr auto comb(int n, int r) const { return fact(n) * factInv(r) * factInv(n - r); } constexpr auto perm(int n, int r) const { return fact(n) * factInv(n - r); } };} namespace mtd { template <class Node, class Cost, class Lambda> auto bfs(const Graph<Node, Cost>& graph, const Node& root, const Lambda& lambda) { auto n = graph.size(); std::vector<bool> used(n); used[root] = true; std::queue<Node> q; q.emplace(root); while (!q.empty()) { auto from = q.front(); q.pop(); for (const auto& [to, cost] : graph.getEdges(from)) { if (used[to]) { continue; } q.emplace(to); used[to] = true; lambda(from, to, cost); } } }} namespace mtd { template <class Node, class Cost, class Lambda> auto treeDP(const Graph<Node, Cost>& tree, Node root, const Lambda& lambda) { auto n = tree.size(); std::vector<Node> in(n); for (const auto& [f, t] : tree.getEdgesExcludeCost()) if (f < t) { ++in[f]; ++in[t]; } std::queue<Node> q; std::vector<bool> used(n); for (Node i = 0; i < n; ++i) if (i != root && in[i] == 1) { q.emplace(i); } while (!q.empty()) { auto from = q.front(); q.pop(); used[from] = true; for (const auto& [to, cost] : tree.getEdges(from)) { if (used[to]) { continue; } lambda(from, to, cost); --in[to]; if (to != root && in[to] == 1) { q.emplace(to); } } } }} namespace mtd { template <int MOD, class T = long long> class ModInt { public: T x; constexpr ModInt(T x) : x(x >= 0 ? x % MOD : MOD + (x % MOD)) {} constexpr ModInt() : ModInt(0) {} constexpr auto& operator+=(const ModInt<MOD, T>& m) { x += m.x; if (x >= MOD) { x -= MOD; } return *this; } constexpr auto& operator-=(const ModInt<MOD, T>& m) { x -= m.x; if (x < 0) { x += MOD; } return *this; } constexpr auto& operator*=(const ModInt<MOD, T>& m) { x *= m.x; if (x >= MOD) { x %= MOD; } return *this; } constexpr auto& operator/=(const ModInt<MOD, T>& m) { x *= mtd::Math<ModInt<MOD, T>>::pow(m.x, MOD - 2).x; if (x >= MOD) { x %= MOD; } return *this; } constexpr auto operator+(const ModInt<MOD, T>& m) const { auto t = *this; t += m; return t; } constexpr auto operator-(const ModInt<MOD, T>& m) const { auto t = *this; t -= m; return t; } constexpr auto operator*(const ModInt<MOD, T>& m) const { auto t = *this; t *= m; return t; } constexpr auto operator/(const ModInt<MOD, T>& m) const { auto t = *this; t /= m; return t; } constexpr auto& operator+=(const T& t) { return *this += ModInt<MOD, T>(t); } constexpr auto& operator-=(const T& t) { return *this -= ModInt<MOD, T>(t); } constexpr auto& operator*=(const T& n) { return *this *= ModInt<MOD, T>(n); } constexpr auto& operator/=(const T& n) { return *this /= ModInt<MOD, T>(n); } constexpr auto operator+(const T& t) const { return *this + ModInt<MOD, T>(t); } constexpr auto operator-(const T& t) const { return *this - ModInt<MOD, T>(t); } constexpr auto operator*(const T& t) const { return *this * ModInt<MOD, T>(t); } constexpr auto operator/(const T& t) const { return *this / ModInt<MOD, T>(t); } constexpr friend auto operator+(const T& t, const ModInt<MOD, T>& m) { return m + t; } constexpr friend auto operator-(const T& t, const ModInt<MOD, T>& m) { return -m + t; } constexpr friend auto operator*(const T& t, const ModInt<MOD, T>& m) { return m * t; } constexpr friend auto operator/(const T& t, const ModInt<MOD, T>& m) { return ModInt<MOD, T>(1) / m * t; } constexpr auto operator-() const { return ModInt<MOD, T>(0 - x); } constexpr auto operator!=(const ModInt<MOD, T>& m) const { return x != m.x; } constexpr auto operator==(const ModInt<MOD, T>& m) const { return !(x != m.x); } constexpr friend std::ostream& operator<<(std::ostream& os, const ModInt<MOD, T>& m) { return os << m.x; } constexpr friend std::istream& operator>>(std::istream& is, ModInt<MOD, T>& m) { return is >> m.x; } constexpr auto val() const { return x; } };} namespace mtd { /* * Monoid: 部分木の情報 * edge_f: 辺の情報を親に流す関数: (M, f, t, c) -> M * node_f: 子の情報を親に流す関数: (M, i) -> M */ template <monoid Monoid, class Node, class Cost, class Lambda1, class Lambda2> auto reRootingDP(const Graph<Node, Cost>& graph, const Lambda1& edge_f, const Lambda2& node_f) { constexpr int root = 0; auto n = graph.size(); auto merge = [&](Monoid& m1, const Monoid& m2, Node f = -1, Node t = -1, const Cost& c = Cost()) { m1 = m1.binaryOperation((f == -1 || t == -1) ? m2 : edge_f(m2, f, t, c)); }; std::vector<std::vector<std::tuple<Monoid, Node, Cost>>> partial(n); auto all_merge = [&](Node to) { Monoid val{}; for (const auto& [ad, from, cost] : partial[to]) { merge(val, ad, from, to, cost); } return node_f(val, to); }; std::vector<std::unordered_map<Node, Monoid>> partial_ac(n); std::vector<Monoid> ret_m(n); auto accumulation = [&](Node to) { Monoid val_ord{}; for (const auto& [ad, from, cost] : partial[to]) { partial_ac[to].emplace(from, val_ord); merge(val_ord, ad, from, to, cost); } Monoid val_rord{}; for (auto rit = partial[to].rbegin(); rit != partial[to].rend(); ++rit) { auto [ad, from, cost] = *rit; merge(partial_ac[to][from], val_rord, cost); merge(val_rord, ad, from, to, cost); } ret_m[to] = node_f(val_ord, to); for (auto&& [_, pac] : partial_ac[to]) { pac = node_f(pac, to); } }; treeDP(graph, root, [&](Node f, Node t, const Cost& c) { partial[t].emplace_back(all_merge(f), f, c); }); accumulation(0); bfs(graph, root, [&](Node f, Node t, const Cost& c) { partial[t].emplace_back(partial_ac[f][t], f, c); accumulation(t); }); std::vector<typename Monoid::value_type> ret; for (const auto x : ret_m) { ret.emplace_back(x.m_val); } return ret; }} using ll = long long; constexpr ll MOD = 998244353; using mint = mtd::ModInt<MOD>; auto math = mtd::Math<mint>(); struct S { mint m; ll s; constexpr S(const mint& m, const ll s) : m(m), s(s) {} constexpr S() : S(0, 0) {} }; int main() { std::cin.tie(0); std::ios::sync_with_stdio(0); ll n; std::cin >> n; std::vector<ll> a(n); for (auto i : std::views::iota(0, n)) { std::cin >> a[i]; } auto graph = mtd::Graph<>(n); for ([[maybe_unused]] auto _ : std::views::iota(0, n - 1)) { int u, v; std::cin >> u >> v; graph.addEdgeUndirected(u - 1, v - 1); } std::vector<mint> at; for (auto x : a) { auto size = std::to_string(x).size(); at.emplace_back(math.pow(10, size)); } auto op = [](const S& a, const S& b) { return S(a.m + b.m, a.s + b.s); }; using M = mtd::Monoid<S, S(0, 0), decltype(op)>; auto edge_f = [&](const M& m, int f, int t, int c) { return M(S(m.m_val.m * at[t] + m.m_val.s * a[t], m.m_val.s)); }; auto node_f = [&](const M& m, int i) { return M(S(m.m_val.m + a[i], m.m_val.s + 1)); }; auto dp = mtd::reRootingDP<M>(graph, edge_f, node_f); mint ans = 0; for (auto x : dp) { ans += x.m; } std::cout << ans << std::endl; }