Codeforces Round #353 Div2 C, D
C. Money Transfers
解法
合計すると0になる連続部分列をできるだけ多くすれば良い。
コード
#include <bits/stdc++.h> using namespace std; template <class T, class U> void chmax(T &t, U f) { if (t < f) t = f; } int main() { cin.tie(0); ios::sync_with_stdio(false); int N; cin >> N; vector<int64_t> a(N); for (int i = 0; i < N; ++i) cin >> a[i]; map<int64_t, int> dp; int64_t x = 0; for (int i = 0; i < N; ++i) { x += a[i]; dp[x]++; } int ans = 0; for (const auto &p : dp) chmax(ans, p.second); cout << (N - ans) << endl; }
D. Tree Construction
解法
すでにツリーに含まれる数字の中でa[i]より大きい最小の数字rとa[i]より小さい最大の数字lを取り出すと、a[i]の親はどちらか一方に必ず定まる。これはrがrより小さい子を持っているか、あるいはlがlより大きい子を持っているかによる。(必ずどちらか一方が成り立つ)
コード
#include <bits/stdc++.h> using namespace std; int main() { cin.tie(0); ios::sync_with_stdio(false); int N; cin >> N; vector<int> a(N); for (int i = 0; i < N; ++i) cin >> a[i]; set<int> s; s.insert(a[0]); s.insert(a[1]); map<int, int> parent; parent[a[1]] = a[0]; map<int, pair<int, int>> children; if (a[0] > a[1]) children[a[0]] = {a[1], -1}; else children[a[0]] = {-1, a[1]}; for (int i = 2; i < N; ++i) { auto it = s.lower_bound(a[i]); if (it == s.begin()) { int r = *it; if (!children.count(r)) children[r] = {-1, -1}; children[r].first = a[i]; parent[a[i]] = r; } else if (it == s.end()) { it--; int l = *it; if (!children.count(l)) children[l] = {-1, -1}; children[l].second = a[i]; parent[a[i]] = l; } else { int r = *it; it--; int l = *it; if (children.count(l) && children[l].second != -1) { if (!children.count(r)) children[r] = {-1, -1}; children[r].first = a[i]; parent[a[i]] = r; } else if (children.count(r) && children[r].first != -1) { if (!children.count(l)) children[l] = {-1, -1}; children[l].second = a[i]; parent[a[i]] = l; } else { cerr << i << endl; assert(false); } } s.insert(a[i]); } for (int i = 1; i < N; ++i) { if (i > 1) cout << " "; cout << parent[a[i]]; } cout << endl; }