結果
問題 | No.2504 NOT Path Painting |
ユーザー | suisen |
提出日時 | 2023-07-22 17:46:23 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
TLE
|
実行時間 | - |
コード長 | 5,732 bytes |
コンパイル時間 | 1,541 ms |
コンパイル使用メモリ | 105,688 KB |
実行使用メモリ | 13,884 KB |
最終ジャッジ日時 | 2024-09-22 17:20:14 |
合計ジャッジ時間 | 10,559 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge4 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
13,884 KB |
testcase_01 | AC | 380 ms
6,944 KB |
testcase_02 | AC | 407 ms
6,944 KB |
testcase_03 | AC | 411 ms
6,944 KB |
testcase_04 | AC | 412 ms
6,944 KB |
testcase_05 | AC | 415 ms
6,944 KB |
testcase_06 | AC | 415 ms
6,940 KB |
testcase_07 | AC | 414 ms
6,944 KB |
testcase_08 | AC | 416 ms
6,940 KB |
testcase_09 | AC | 411 ms
6,940 KB |
testcase_10 | AC | 412 ms
6,944 KB |
testcase_11 | AC | 411 ms
6,940 KB |
testcase_12 | AC | 443 ms
6,948 KB |
testcase_13 | TLE | - |
testcase_14 | -- | - |
testcase_15 | -- | - |
testcase_16 | -- | - |
testcase_17 | -- | - |
testcase_18 | -- | - |
testcase_19 | -- | - |
testcase_20 | -- | - |
ソースコード
// TLE 区間DP 苦行 #include <deque> #include <iostream> #include <tuple> #include <vector> #include <atcoder/modint> using mint = atcoder::modint998244353; struct SubtreeSize { SubtreeSize(int n, const std::vector<std::vector<int>>& g): _n(n), _par(_n, -1), _siz(_n, 1) { auto dfs = [&](auto dfs, int u, int p) -> int { _par[u] = p; for (int v : g[u]) if (v != p) { _siz[u] += dfs(dfs, v, u); } return _siz[u]; }; dfs(dfs, 0, -1); } // u の親を p としたときの、部分木 u のサイズ int operator()(int u, int p) const { return _par[u] == p ? _siz[u] : _n - _siz[p]; } // 解説の t (隣接点が ng1 の場合) int t(int u, int ng1) const { return _n - (*this)(ng1, u); } // 解説の t (隣接点が ng1, ng2 の場合) int t(int u, int ng1, int ng2) const { return _n - (*this)(ng1, u) - (*this)(ng2, u); } private: int _n; std::vector<int> _par, _siz; }; int edge_num(int n) { return (n * (n + 1)) >> 1; } int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); auto solve = [&]{ int n; std::cin >> n; std::vector<std::vector<int>> g(n); for (int i = 0; i < n - 1; ++i) { int u, v; std::cin >> u >> v; --u, --v; g[u].push_back(v); g[v].push_back(u); } const int m = edge_num(n); const mint inv_m = mint(m).inv(); SubtreeSize subtree_size { n, g }; std::vector<mint> ans_f(n, 0); for (int x = 0; x < n; ++x) { int u_x = edge_num(n); for (int y : g[x]) { u_x -= edge_num(subtree_size(y, x)); } ans_f[x] = m * mint(m - u_x).inv(); } std::vector<std::vector<mint>> ans_g(n, std::vector<mint>(n)); // par[x][y] := x を根とする木における y の親 std::vector<std::vector<int>> par(n, std::vector<int>(n, -1)); // x, y, A_{x,y}, B_{x,y} std::deque<std::tuple<int, int, mint, mint>> dq; for (int x = 0; x < n; ++x) { ans_g[x][x] = ans_f[x]; // s_x(x) const int s_x_x = n; // u_{x,x}(x) int u_xx_x = edge_num(n); for (int y : g[x]) { // s_x(y) const int s_x_y = subtree_size(y, x); u_xx_x -= edge_num(s_x_y); } for (int y : g[x]) { // s_x(y) const int s_x_y = subtree_size(y, x); // u_{x,y}(x) const int u_xy_x = u_xx_x - s_x_y * (s_x_x - s_x_y); const mint Axy = u_xy_x * ans_f[x]; const mint Bxy = 0; par[x][y] = x; dq.emplace_back(x, y, Axy, Bxy); } } while (dq.size()) { auto [x, y, Axy, Bxy] = dq.front(); dq.pop_front(); // x を根とした木における y の親 const int par_y = par[x][y]; // s_x(y) const int s_x_y = subtree_size(y, par_y); // u_{x,y}(y) int u_xy_y = edge_num(s_x_y); for (int w : g[y]) if (w != par_y) { u_xy_y -= edge_num(subtree_size(w, y)); } // t_{x,y}(y) const int t_xy_y = s_x_y; ans_g[x][y] = Axy + u_xy_y * ans_f[y] + Bxy; // sum _ {z in Pxy-{y}} t_{x,y}(y) t_{x,y}(z) g(y,z) の計算 int prev_z = y, z = par_y; while (z != x) { const int next_z = par[x][z]; // t_{x,y}(z) // z の 1 つ前と 1 つ後が N_{x,y}(z) に含まれる頂点 const int t_xy_z = subtree_size.t(z, prev_z, next_z); ans_g[x][y] += t_xy_y * t_xy_z * ans_g[y][z]; std::tie(prev_z, z) = std::make_tuple(z, next_z); } // t_{x,y}(x) const int t_xy_x = subtree_size.t(x, prev_z); ans_g[x][y] = (1 + ans_g[x][y] * inv_m) * (1 - t_xy_x * t_xy_y * inv_m).inv(); for (int w : g[y]) if (w != par_y) { // t_{x,w}(x) const int t_xw_x = t_xy_x; // s_{x}(w) const int s_x_w = subtree_size(w, y); // t_{x,w}(y) const int t_xw_y = t_xy_y - s_x_w; // u_{x,w}(y) const int u_xw_y = u_xy_y - s_x_w * (s_x_y - s_x_w); // A_{x,w} const mint Axw = Axy + u_xw_y * ans_f[y]; // B_{x,w} mint Bxw = Bxy + t_xw_y * t_xw_x * ans_g[x][y]; // Bxw に sum_{z in Pxy-{y}} t_{x,w}(y) * t_{x,w}(z) * g(y,z) を足して更新 int prev_z = y, z = par_y; while (z != x) { const int next_z = par[x][z]; // t_{x,w}(z) const int t_xw_z = subtree_size.t(z, prev_z, next_z); // t_{x,w}(y) * t_{x,w}(z) * g(y, z) Bxw += t_xw_y * t_xw_z * ans_g[y][z]; std::tie(prev_z, z) = std::make_tuple(z, next_z); } par[x][w] = y; dq.emplace_back(x, w, Axw, Bxw); } } mint ans = 1; for (int x = 0; x < n; ++x) { for (int y = 0; y <= x; ++y) { ans += ans_g[x][y] * inv_m; } } std::cout << ans.val() << '\n'; }; int t; std::cin >> t; while (t --> 0) { solve(); } return 0; }