Educational Codeforces Round 6 部分題解
阿新 • • 發佈:2021-10-21
C. Pearls in a Row
直接貪心做即可。
但是注意如果最後一段不合法,要把最後一段合進上一段,如果整個序列都不合法就無解。
#易錯警示:仔細考慮無解條件,可能還有別的坑。
const int MAXN = 3e5 + 10; int n, aa[MAXN]; int lisan[MAXN], cnt; int nums[MAXN], tot; void Add(int x) { if (nums[aa[x]] == 1) ++tot; ++nums[aa[x]]; } void Del(int x) { --nums[aa[x]]; if (nums[aa[x]] == 1) --tot; } int main() { n = read(); rep (i, 1, n) { aa[i] = read(); lisan[++cnt] = aa[i]; } std::sort(lisan + 1, lisan + 1 + cnt); cnt = (int) (std::unique(lisan + 1, lisan + 1 + cnt) - lisan - 1); int tl = 1; std::vector<std::pair<int, int> > anss; rep (i, 1, n) { aa[i] = (int) (std::lower_bound(lisan + 1, lisan + 1 + cnt, aa[i]) - lisan); Add(i); if (tot) { anss.push_back({tl, i}); while (tl <= i) Del(tl++); } } if (tl != n + 1) { if (!anss.size()) { puts("-1"); return 0; } anss[anss.size() - 1].se = n; } printf("%d\n", (int) anss.size()); for (auto v : anss) printf("%d %d\n", v.fi, v.se); return 0; }
D. Professor GukiZ and Two Arrays
只做一次交換的可以直接 \(O(nm)\) 做完。
考慮兩次交換的實質是找到一對 \(a_i + a_j\) 和一對 \(b_k + b_l\) 進行交換,於是可以大力把所有的 \(a_i + a_j\) 和 \(b_i + b_j\) 分別求出來,然後二分一下或者雙指標掃一掃(類似歸併排序的合併)就可以了。
const int MAXN = 2000 + 10; int n, m; lli aa[MAXN], bb[MAXN]; lli suma, sumb; struct S { lli sum; int a, b; }; std::vector<S> swpa, swpb; bool cmp(S x, S y) { return x.sum < y.sum; } std::pair<int, int> swapping[2]; int main() { n = read(); rep (i, 1, n) suma += (aa[i] = read()); m = read(); rep (i, 1, m) sumb += (bb[i] = read()); rep (i, 1, n) rep (j, i + 1, n) { swpa.push_back({aa[i] + aa[j], i, j}); } std::sort(ALL(swpa), cmp); rep (i, 1, m) rep (j, i + 1, m) { swpb.push_back({bb[i] + bb[j], i, j}); } std::sort(ALL(swpb), cmp); lli tans = std::abs(suma - sumb); rep (i, 1, n) { rep (j, 1, m) { lli ttans = std::abs(suma - sumb + 2 * bb[j] - 2 * aa[i]); if (ttans < tans) { tans = ttans; swapping[0] = {i, j}; } } } int p1 = 0, p2 = 0; while (p1 < (int) swpa.size() && p2 < (int) swpb.size()) { lli tmp = suma - sumb + 2 * swpb[p2].sum - 2 * swpa[p1].sum; if (std::abs(tmp) < tans) { tans = std::abs(tmp); swapping[0] = {swpa[p1].a, swpb[p2].a}; swapping[1] = {swpa[p1].b, swpb[p2].b}; } if (tmp > 0) ++p1; else ++ p2; } printf("%lld\n", tans); int knds = swapping[1].fi ? 2 : (swapping[0].fi ? 1 : 0); printf("%d\n", knds); rep (i, 0, knds - 1) printf("%d %d\n", swapping[i].fi, swapping[i].se); return 0; }
E. New Year Tree
線段樹維護子樹資訊板子題。
#易錯警示:線段樹肌肉記憶真的很容易寫錯,特別是遞迴區間那一部分。
const int MAXN = 4e5 + 10; int n, m; std::vector<int> G[MAXN]; lli cols[MAXN]; int dfn[MAXN], idx[MAXN], ts; int siz[MAXN]; void dfs(int u, int fa) { dfn[u] = ++ts; idx[dfn[u]] = u; siz[u] = 1; forall (G[u], i) { int v = G[u][i]; if (v == fa) continue; dfs(v, u); siz[u] += siz[v]; } } namespace Segt { lli col[MAXN << 2]; int tag[MAXN << 2]; #define ls (p << 1) #define rs (p << 1 | 1) void Update(int p) { col[p] = col[ls] | col[rs]; } void buildTree(int p, int l, int r, lli *cc) { tag[p] = -1; if (l == r) { col[p] = (1ll << cc[idx[l]]); return; } int mid = (l + r) >> 1; buildTree(ls, l, mid, cc); buildTree(rs, mid + 1, r, cc); Update(p); } void Mod(int p, int color) { col[p] = (1ll << color); tag[p] = color; } void Pushdown(int p) { if (tag[p] == -1) return; Mod(ls, tag[p]); Mod(rs, tag[p]); tag[p] = -1; } void Modify(int p, int l, int r, int ll, int rr, int color) { if (l == ll && rr == r) { Mod(p, color); return; } Pushdown(p); int mid = (l + r) >> 1; if (rr <= mid) Modify(ls, l, mid, ll, rr, color); else if (mid + 1 <= ll) Modify(rs, mid + 1, r, ll, rr, color); else { Modify(ls, l, mid, ll, mid, color); Modify(rs, mid + 1, r, mid + 1, rr, color); } Update(p); } lli Query(int p, int l, int r, int ll, int rr) { if (l == ll && rr == r) return col[p]; Pushdown(p); int mid = (l + r) >> 1; if (rr <= mid) return Query(ls, l, mid, ll, rr); else if (mid + 1 <= ll) return Query(rs, mid + 1, r, ll, rr); else return Query(ls, l, mid, ll, mid) | Query(rs, mid + 1, r, mid + 1, rr); } } int popcount(lli x) { int r = 0; while (x) { r += (x & 1); x >>= 1; } return r; } int main() { n = read(); m = read(); rep (i, 1, n) cols[i] = read(); rep (i, 1, n - 1) { int u = read(); int v = read(); G[u].push_back(v); G[v].push_back(u); } dfs(1, 0); Segt::buildTree(1, 1, n, cols); while (m --> 0) { int t = read(); if (t == 1) { int v = read(); int c = read(); Segt::Modify(1, 1, n, dfn[v], dfn[v] + siz[v] - 1, c); } else { int v = read(); printf("%d\n", (int) popcount(Segt::Query(1, 1, n, dfn[v], dfn[v] + siz[v] - 1))); } } return 0; }