結果
問題 | No.2987 Colorful University of Tree |
ユーザー | 👑 hos.lyric |
提出日時 | 2024-12-13 08:16:46 |
言語 | C++14 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 802 ms / 5,000 ms |
コード長 | 9,510 bytes |
コンパイル時間 | 2,339 ms |
コンパイル使用メモリ | 141,172 KB |
実行使用メモリ | 65,080 KB |
最終ジャッジ日時 | 2024-12-13 08:17:14 |
合計ジャッジ時間 | 26,305 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge4 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1 ms
6,820 KB |
testcase_01 | AC | 2 ms
6,820 KB |
testcase_02 | AC | 151 ms
6,816 KB |
testcase_03 | AC | 185 ms
6,820 KB |
testcase_04 | AC | 186 ms
6,820 KB |
testcase_05 | AC | 528 ms
34,128 KB |
testcase_06 | AC | 134 ms
11,816 KB |
testcase_07 | AC | 93 ms
10,376 KB |
testcase_08 | AC | 452 ms
31,136 KB |
testcase_09 | AC | 140 ms
15,376 KB |
testcase_10 | AC | 675 ms
47,468 KB |
testcase_11 | AC | 534 ms
41,172 KB |
testcase_12 | AC | 800 ms
63,964 KB |
testcase_13 | AC | 548 ms
41,232 KB |
testcase_14 | AC | 547 ms
41,024 KB |
testcase_15 | AC | 688 ms
41,668 KB |
testcase_16 | AC | 656 ms
50,736 KB |
testcase_17 | AC | 682 ms
54,400 KB |
testcase_18 | AC | 582 ms
41,088 KB |
testcase_19 | AC | 549 ms
41,164 KB |
testcase_20 | AC | 571 ms
41,348 KB |
testcase_21 | AC | 536 ms
41,200 KB |
testcase_22 | AC | 546 ms
41,136 KB |
testcase_23 | AC | 802 ms
65,080 KB |
testcase_24 | AC | 226 ms
7,936 KB |
testcase_25 | AC | 223 ms
7,936 KB |
testcase_26 | AC | 226 ms
7,932 KB |
testcase_27 | AC | 235 ms
7,936 KB |
testcase_28 | AC | 229 ms
7,824 KB |
testcase_29 | AC | 14 ms
6,820 KB |
testcase_30 | AC | 78 ms
6,820 KB |
testcase_31 | AC | 77 ms
6,820 KB |
testcase_32 | AC | 188 ms
6,820 KB |
testcase_33 | AC | 232 ms
12,264 KB |
testcase_34 | AC | 283 ms
16,648 KB |
testcase_35 | AC | 299 ms
28,384 KB |
testcase_36 | AC | 576 ms
38,268 KB |
testcase_37 | AC | 77 ms
10,676 KB |
testcase_38 | AC | 320 ms
28,436 KB |
testcase_39 | AC | 73 ms
9,572 KB |
testcase_40 | AC | 404 ms
31,196 KB |
99_evil_hack_000.txt | AC | 2 ms
6,820 KB |
ソースコード
// no proof, please hack me #include <cassert> #include <cmath> #include <cstdint> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <bitset> #include <complex> #include <deque> #include <functional> #include <iostream> #include <limits> #include <map> #include <numeric> #include <queue> #include <random> #include <set> #include <sstream> #include <string> #include <unordered_map> #include <unordered_set> #include <utility> #include <vector> using namespace std; using Int = long long; template <class T1, class T2> ostream &operator<<(ostream &os, const pair<T1, T2> &a) { return os << "(" << a.first << ", " << a.second << ")"; }; template <class T> ostream &operator<<(ostream &os, const vector<T> &as) { const int sz = as.size(); os << "["; for (int i = 0; i < sz; ++i) { if (i >= 256) { os << ", ..."; break; } if (i > 0) { os << ", "; } os << as[i]; } return os << "]"; } template <class T> void pv(T a, T b) { for (T i = a; i != b; ++i) cerr << *i << " "; cerr << endl; } template <class T> bool chmin(T &t, const T &f) { if (t > f) { t = f; return true; } return false; } template <class T> bool chmax(T &t, const T &f) { if (t < f) { t = f; return true; } return false; } #define COLOR(s) ("\x1b[" s "m") // !!!Modifies ns and edges!!! // n: modified regular bipartite graph // d := max degree = edge chromatic number // iss[c]: edges of color c \in [0, d) // colors[i]: color of edge i struct BipartiteEdgeColoring { int ns[2]; vector<pair<int, int>> edges; int n; int d; vector<int> colors; vector<vector<int>> iss; BipartiteEdgeColoring() {} BipartiteEdgeColoring(int n0, int n1) : ns{n0, n1}, edges() {} void ae(int u, int v) { assert(0 <= u); assert(u < ns[0]); assert(0 <= v); assert(v < ns[1]); edges.emplace_back(u, v); } void run() { const int m = edges.size(); vector<int> deg[2]; for (int s = 0; s < 2; ++s) deg[s].assign(ns[s], 0); for (const auto &edge : edges) { ++deg[0][edge.first]; ++deg[1][edge.second]; } d = 0; for (int s = 0; s < 2; ++s) for (int u = 0; u < ns[s]; ++u) if (d < deg[s][u]) d = deg[s][u]; // Merge vertices of small degree. for (int s = 0; s < 2; ++s) { priority_queue<pair<int, int>, vector<pair<int, int>>, std::greater<pair<int, int>>> que; par.resize(ns[s]); for (int u = 0; u < ns[s]; ++u) que.emplace(deg[s][u], par[u] = u); for (; ; ) { if (!que.size()) break; const auto p0 = que.top(); que.pop(); if (!que.size()) break; const auto p1 = que.top(); que.pop(); if (p0.first + p1.first > d) break; par[p0.second] = p1.second; que.emplace(p0.first + p1.first, p1.second); } int nn = 0; vector<int> ids(ns[s], -1); for (int u = 0; u < ns[s]; ++u) if (par[u] == u) ids[u] = nn++; ns[s] = nn; if (s == 0) { for (auto &edge : edges) edge.first = ids[root(edge.first)]; } else { for (auto &edge : edges) edge.second = ids[root(edge.second)]; } } // Add edges to make the graph d-regular. n = max(ns[0], ns[1]); for (int s = 0; s < 2; ++s) deg[s].assign(n, 0); for (const auto &edge : edges) { ++deg[0][edge.first]; ++deg[1][edge.second]; } for (int u = 0, v = 0; ; ) { for (; u < n && deg[0][u] >= d; ++u) {} for (; v < n && deg[1][v] >= d; ++v) {} if (u == n && v == n) break; edges.emplace_back(u, v); ++deg[0][u]; ++deg[1][v]; } iss.clear(); vector<int> is(n * d); for (int i = 0; i < n * d; ++i) is[i] = i; rec(is); // Remove added edges. colors.assign(m, -1); for (int k = 0; k < d; ++k) { iss[k].erase(std::lower_bound(iss[k].begin(), iss[k].end(), m), iss[k].end()); for (const int i : iss[k]) colors[i] = k; } } vector<int> par; int root(int u) { return (par[u] == u) ? u : (par[u] = root(par[u])); } // is: k-regular void rec(vector<int> is) { if (!is.size()) return; const int k = is.size() / n; if (k == 1) { std::sort(is.begin(), is.end()); iss.push_back(is); } else if (k % 2 != 0) { if (iss.size()) { is.insert(is.end(), iss.back().begin(), iss.back().end()); iss.pop_back(); rec(is); } else { // Add (2^e - k) bad matchings to find a perfect matching. const int e = (31 - __builtin_clz(k)) + 1; vector<int> ma(n); for (int u = 0; u < n; ++u) ma[u] = ~u; for (; ; ) { auto js = is; for (const int j : ma) for (int l = 0; l < (1 << e) - k; ++l) js.push_back(j); for (int f = e; --f >= 0; ) { const auto jss = euler(js); int numBads[2] = {}; for (int s = 0; s < 2; ++s) for (const int i : jss[s]) if (i < 0) ++numBads[s]; js = jss[(numBads[0] <= numBads[1]) ? 0 : 1]; } ma.swap(js); bool good = true; for (const int j : ma) if (j < 0) { good = false; break; } if (good) break; } std::sort(ma.begin(), ma.end()); iss.push_back(ma); std::sort(is.begin(), is.end()); vector<int> iis; auto it = ma.begin(); for (const int i : is) { for (; it != ma.end() && *it < i; ++it) {} if (!(it != ma.end() && *it == i)) iis.push_back(i); } rec(iis); } } else { const auto jss = euler(is); for (int s = 0; s < 2; ++s) rec(jss[s]); } } // Take Eulerian circuit and take edges alternately. vector<vector<int>> euler(const vector<int> &is) { const int k = is.size() / n; vector<int> pt(n + n); for (int u = 0; u < n + n; ++u) pt[u] = u * k; vector<pair<int, int>> xvs((n + n) * k); for (int x = 0; x < n * k; ++x) { const int i = is[x]; int u, v; if (i >= 0) { u = edges[i].first; v = n + edges[i].second; } else { u = ~i; v = n + ~i; } xvs[pt[u]++] = std::make_pair(x, v); xvs[pt[v]++] = std::make_pair(x, u); } vector<int> used(n * k, 0); int y = 0; vector<vector<int>> jss(2, vector<int>(n * (k / 2))); vector<int> stack; for (int u0 = 0; u0 < n; ++u0) { for (stack.push_back(u0); stack.size(); ) { const int u = stack.back(); if (pt[u] > u * k) { --pt[u]; const int x = xvs[pt[u]].first; const int v = xvs[pt[u]].second; if (!used[x]) { used[x] = 1; jss[y & 1][y >> 1] = is[x]; ++y; stack.push_back(v); } } else { stack.pop_back(); } } } return jss; } }; //////////////////////////////////////////////////////////////////////////////// vector<int> greedy(const vector<int> °, int m) { const int n = deg.size(); priority_queue<pair<int, int>> que; for (int i = 0; i < m; ++i) que.emplace(m, i); vector<pair<int, int>> dus(n); for (int u = 0; u < n; ++u) dus[u] = make_pair(deg[u], u); sort(dus.begin(), dus.end(), greater<pair<int, int>>{}); vector<int> ret(n, 0); for (const auto &du : dus) { const int c = que.top().first; const int i = que.top().second; que.pop(); if (c < du.first) return {}; que.emplace(c - du.first, i); ret[du.second] = i; } return ret; } int getM(const vector<int> °) { const int n = deg.size(); Int m = 0; for (; !(2 * n - 2 <= m * m); ++m) {} for (int u = 0; u < n; ++u) chmax<Int>(m, deg[u]); // girigiri, but too few odd Int sum = 0; for (int u = 0; u < n; ++u) sum += deg[u] / 2; for (; !(sum <= m * (m/2)); ++m) {} return m; } namespace exper { int N; vector<int> deg; Int counter; void test() { // cerr<<"[test] "<<deg<<endl; ++counter; const int m = getM(deg); const auto res = greedy(deg, m); if (!res.size()) { cerr << "FAIL " << deg << " " << m << endl; assert(false); } } void dfs(int u, int e, int d) { if (e > (N - u) * d) return; if (u == N) { test(); } else { for (chmin(d, e); d >= 0; --d) { deg[u] = 1 + d; dfs(u + 1, e - d, d); } } } void run() { for (N = 2; ; ++N) { deg.resize(N); counter = 0; dfs(0, N - 2, N - 2); cerr << "PASSED N = " << N << ": counter = " << counter << endl; } } } // exper // DONE N = 83: counter = 18004327 int N; vector<int> C; vector<vector<int>> E; int main() { // exper::run(); for (int numCases; ~scanf("%d", &numCases); ) { for (int caseId = 1; caseId <= numCases; ++caseId) { scanf("%d", &N); C.resize(N); E.resize(N); for (int u = 0; u < N; ++u) { scanf("%d", &C[u]); E[u].resize(C[u]); for (int c = 0; c < C[u]; ++c) { scanf("%d", &E[u][c]); --E[u][c]; } } const int M = getM(C); const auto res = greedy(C, M); /* side 0: endpoints of edge side 1: edge from same vertex color */ BipartiteEdgeColoring bec(N - 1, M); for (int u = 0; u < N; ++u) { for (int c = 0; c < C[u]; ++c) { bec.ae(E[u][c], res[u]); } } bec.run(); assert(bec.d <= M); printf("%d\n", M); int id = 0; for (int u = 0; u < N; ++u) { printf("%d", res[u] + 1); for (int c = 0; c < C[u]; ++c) { printf(" %d", bec.colors[id++] + 1); } puts(""); } } #ifndef LOCAL break; #endif } return 0; }