yukicoder No. 901 K-ary εxtrεεmε 別解
解法
木の辺に値が書かれていて、最初はすべて が書かれているとします。
について、 パスに含まれている辺にすべて を加算すると、 以上の数が書かれた辺の重みの合計が答えです。 が書かれた辺の重みの合計を求め、全体から引くことで求められます。区間加算・区間の最小値とその個数の取得ができる遅延セグメント木を HLD に載せると処理できます。
HLD は クエリを通して共通のものを使いたいので、答えを求めた後、 を加えたパスに を加えて値を に戻す必要があります。
実装
#include <bits/stdc++.h> using namespace std; const int INF = 10000000; struct monoid{ int mn; long long sum; monoid(): mn(INF), sum(0){ } }; monoid op(monoid A, monoid B){ monoid ans; ans.mn = min(A.mn, B.mn); if (ans.mn == A.mn){ ans.sum += A.sum; } if (ans.mn == B.mn){ ans.sum += B.sum; } return ans; } struct lazy_segment_tree{ int N; vector<int> lazy; vector<monoid> ST; lazy_segment_tree(){ } lazy_segment_tree(vector<int> w){ int N2 = w.size(); N = 1; while (N < N2){ N *= 2; } ST = vector<monoid>(N * 2 - 1); for (int i = 0; i < N2; i++){ ST[N - 1 + i].mn = 0; ST[N - 1 + i].sum = w[i]; } for (int i = N - 2; i >= 0; i--){ ST[i] = op(ST[i * 2 + 1], ST[i * 2 + 2]); } lazy = vector<int>(N * 2 - 1, 0); } void push(int i){ if (i < N - 1){ lazy[i * 2 + 1] += lazy[i]; lazy[i * 2 + 2] += lazy[i]; } ST[i].mn += lazy[i]; lazy[i] = 0; } void range_add(int L, int R, int x, int i, int l, int r){ push(i); if (r <= L || R <= l){ return; } else if (L <= l && r <= R){ lazy[i] += x; push(i); } else { int m = (l + r) / 2; range_add(L, R, x, i * 2 + 1, l, m); range_add(L, R, x, i * 2 + 2, m, r); ST[i] = op(ST[i * 2 + 1], ST[i * 2 + 2]); } } void range_add(int L, int R, int x){ range_add(L, R, x, 0, 0, N); } monoid all(){ push(0); return ST[0]; } }; struct heavy_light_decomposition{ vector<int> p, sz, in, next; lazy_segment_tree ST; heavy_light_decomposition(vector<int> &p, vector<vector<int>> &c, vector<int> &w): p(p){ int N = p.size(); sz = vector<int>(N); dfs1(c); in = vector<int>(N); next = vector<int>(N, 0); int t = 0; dfs2(c, t); vector<int> w2(N, 0); for (int i = 0; i < N; i++){ w2[in[i]] = w[i]; } ST = lazy_segment_tree(w2); } void dfs1(vector<vector<int>> &c, int v = 0){ sz[v] = 1; for (int &w : c[v]){ dfs1(c, w); sz[v] += sz[w]; if (sz[w] > sz[c[v][0]]){ swap(w, c[v][0]); } } } void dfs2(vector<vector<int>> &c, int &t, int v = 0){ in[v] = t; t++; for (int w : c[v]){ if (w == c[v][0]){ next[w] = next[v]; } else { next[w] = w; } dfs2(c, t, w); } } int lca(int u, int v){ while (true){ if (in[u] > in[v]){ swap(u, v); } if (next[u] == next[v]){ return u; } v = p[next[v]]; } } void path_add(int u, int v, int x){ int w = lca(u, v); while (next[u] != next[w]){ ST.range_add(in[next[u]], in[u] + 1, x); u = p[next[u]]; } ST.range_add(in[w] + 1, in[u] + 1, x); while (next[v] != next[w]){ ST.range_add(in[next[v]], in[v] + 1, x); v = p[next[v]]; } ST.range_add(in[w] + 1, in[v] + 1, x); } monoid get(){ return ST.all(); } }; int main(){ int N; cin >> N; vector<vector<pair<int, int>>> E(N); for (int i = 0; i < N - 1; i++){ int u, v, w; cin >> u >> v >> w; E[u].push_back(make_pair(w, v)); E[v].push_back(make_pair(w, u)); } vector<int> p(N, -1); vector<vector<int>> c(N); vector<int> pw(N); queue<int> q; q.push(0); while (!q.empty()){ int v = q.front(); q.pop(); for (pair<int, int> e : E[v]){ int w = e.second; if (w != p[v]){ p[w] = v; c[v].push_back(w); pw[w] = e.first; q.push(w); } } } long long sum = 0; for (int i = 1; i < N; i++){ sum += pw[i]; } heavy_light_decomposition HLD(p, c, pw); int Q; cin >> Q; for (int i = 0; i < Q; i++){ int k; cin >> k; vector<int> x(k); for (int j = 0; j < k; j++){ cin >> x[j]; } for (int j = 1; j < k; j++){ HLD.path_add(x[0], x[j], 1); } cout << sum - HLD.get().sum << endl; for (int j = 1; j < k; j++){ HLD.path_add(x[0], x[j], -1); } } }
ACPC 2021 Day2 J を一般グラフで解く (実装編)
Nachia さんの考えたアルゴリズムを実装しました。 www.mathenachia.blog
注意
- 簡単なランダムチェッカーを通しています。
- 時間計算量については確認していませんが、ACPC 2021 Day2 J を AC することはできました。
- 下のコードはグラフが入力された場合に答えるコードです。ACPC 2021 Day2 J を AC できるコードは大部分が同じなので掲載しません。以下のリンクから確認してください。 judge.u-aizu.ac.jp
#include <bits/stdc++.h> using namespace std; struct extended_block_cut_tree{ int N, cnt; vector<vector<int>> G; extended_block_cut_tree(vector<vector<int>> &E){ N = E.size(); vector<int> next(N, -1); vector<int> d(N, -1); vector<int> imos(N, 0); for (int i = 0; i < N; i++){ if (d[i] == -1){ d[i] = 0; dfs1(E, next, d, imos, i); } } cnt = 0; G.resize(N + 1); vector<bool> used(N, false); for (int i = 0; i < N; i++){ if (d[i] == 0){ dfs2(E, d, imos, used, cnt, i); } if (E[i].empty()){ G[i].push_back(N + cnt); G[N + cnt].push_back(i); cnt++; G.push_back({}); } } G.pop_back(); } void dfs1(vector<vector<int>> &E, vector<int> &next, vector<int> &d, vector<int> &imos, int v){ for (int w : E[v]){ if (d[w] == -1){ d[w] = d[v] + 1; next[v] = w; dfs1(E, next, d, imos, w); imos[v] += imos[w]; } else if (d[w] < d[v] - 1){ imos[v]++; imos[next[w]]--; } } } void dfs2(vector<vector<int>> &E, vector<int> &d, vector<int> &imos, vector<bool> &used, int b, int v){ used[v] = true; bool ok = false; for (int w : E[v]){ if (d[w] == d[v] + 1 && !used[w]){ if (imos[w] > 0){ if (!ok){ ok = true; G[v].push_back(N + b); G[N + b].push_back(v); } dfs2(E, d, imos, used, b, w); } else { G[v].push_back(N + cnt); G[N + cnt].push_back(v); cnt++; G.push_back({}); dfs2(E, d, imos, used, cnt - 1, w); } } } if (!ok && d[v] > 0){ G[v].push_back(N + b); G[N + b].push_back(v); } } int size(){ return G.size(); } vector<int> &operator [](int v){ return G[v]; } }; struct ford_fulkerson{ struct edge{ int to, rev, cap; edge(int to, int rev, int cap): to(to), rev(rev), cap(cap){ } }; int N; vector<vector<edge>> G; ford_fulkerson(int N): N(N), G(N){ } void add_edge(int from, int to){ G[from].push_back(edge(to, G[to].size(), 1)); G[to].push_back(edge(from, G[from].size() - 1, 0)); } void max_flow(int s, int t, int F){ int flow = 0; while (flow < F){ vector<int> pv(N, -1); vector<int> pe(N, -1); vector<bool> used(N, false); used[s] = true; queue<int> Q; Q.push(s); while (!Q.empty()){ int v = Q.front(); Q.pop(); int cnt = G[v].size(); for (int i = 0; i < cnt; i++){ int w = G[v][i].to; if (!used[w] && G[v][i].cap > 0){ used[w] = true; pv[w] = v; pe[w] = i; Q.push(w); } } } if (!used[t]){ break; } for (int v = t; v != s; v = pv[v]){ G[pv[v]][pe[v]].cap--; G[v][G[pv[v]][pe[v]].rev].cap++; } flow++; } } }; int main(){ int N, M; cin >> N >> M; vector<vector<int>> E(N); for (int i = 0; i < M; i++){ int u, v; cin >> u >> v; u--; v--; E[u].push_back(v); E[v].push_back(u); } extended_block_cut_tree T(E); int V = T.size(); vector<int> p(V, -1); vector<int> d(V, 0); for (int i = 0; i < V; i++){ if (p[i] == -1){ queue<int> Q; Q.push(i); while (!Q.empty()){ int v = Q.front(); Q.pop(); for (int w : T[v]){ if (w != p[v]){ p[w] = v; d[w] = d[v] + 1; Q.push(w); } } } } } vector<int> bp = {N - 1}; bool ok = false; while (true){ int v = bp.back(); if (v == 0){ ok = true; break; } if (d[v] == 0){ break; } bp.push_back(p[v]); } vector<int> ans(N, 0); if (!ok){ for (int i = 1; i < N - 1; i++){ ans[i] = N - 3; } } else { int L = bp.size(); vector<bool> is_art(N, false); int art_cnt = 0; for (int i = 0; i < L; i++){ if (1 <= bp[i] && bp[i] < N - 1 && T[bp[i]].size() >= 2){ is_art[bp[i]] = true; art_cnt++; } } vector<vector<pair<int, int>>> edge(V - N); for (int i = 0; i < N; i++){ for (int j : E[i]){ if (i < j){ int v; if (d[i] >= d[j]){ v = p[i]; } else { v = p[j]; } edge[v - N].push_back(make_pair(i, j)); } } } vector<int> id(N); for (int i = 1; i < L; i += 2){ int cnt = 0; vector<int> id2; for (int j : T[bp[i]]){ id[j] = cnt; id2.push_back(j); cnt++; } if (cnt == 2){ continue; } vector<vector<int>> E2(cnt); for (pair<int, int> P : edge[bp[i] - N]){ int u = id[P.first]; int v = id[P.second]; E2[u].push_back(v); E2[v].push_back(u); } int s = id[bp[i - 1]]; int t = id[bp[i + 1]]; ford_fulkerson G(cnt * 2); for (int j = 0; j < cnt; j++){ G.add_edge(j, cnt + j); } for (int j = 0; j < cnt; j++){ for (int k : E2[j]){ G.add_edge(cnt + j, k); } } G.max_flow(cnt + s, t, 2); vector<vector<int>> path; for (ford_fulkerson::edge e : G.G[t]){ if (e.cap > 0 && e.to != cnt + t){ vector<int> tmp = {t}; int v = e.to; while (v != cnt + s){ if (v < cnt){ tmp.push_back(v); } for (ford_fulkerson::edge e : G.G[v]){ if (e.cap > 0){ v = e.to; break; } } } tmp.push_back(s); path.push_back(tmp); } } reverse(path[0].begin(), path[0].end()); reverse(path[1].begin(), path[1].end()); for (int j = 0; j < 2; j++){ int cnt1 = path[1].size(); vector<bool> is_path1(cnt, false); for (int k = 1; k < cnt1 - 1; k++){ is_path1[path[1][k]] = true; } vector<vector<int>> E3(cnt); for (int u = 0; u < cnt; u++){ for (int v : E2[u]){ if (!is_path1[u] && !is_path1[v]){ E3[u].push_back(v); } } } extended_block_cut_tree T2(E3); int V2 = T2.size(); vector<int> p2(V2, -1); queue<int> Q2; Q2.push(s); while (!Q2.empty()){ int v = Q2.front(); Q2.pop(); for (int w : T2[v]){ if (w != p2[v]){ p2[w] = v; Q2.push(w); } } } vector<int> path2; path2.push_back(t); for (int v = p2[t]; v != s; v = p2[v]){ if (v < cnt && T2[v].size() >= 2){ path2.push_back(v); } } path2.push_back(s); reverse(path2.begin(), path2.end()); path[0] = path2; int cnt0 = path[0].size(); for (int k = 0; k < cnt0 - 1; k++){ int u = path[0][k]; int v = path[0][k + 1]; bool ee = false; for (int w : E2[u]){ if (w == v){ ee = true; } } if (!ee){ E2[u].push_back(v); E2[v].push_back(u); } } vector<bool> gray(cnt, true); for (int k = 0; k < cnt0; k++){ gray[path[0][k]] = false; } for (int k = 0; k < cnt1; k++){ gray[path[1][k]] = false; } vector<bool> re(cnt, false); vector<bool> used2(cnt, false); for (int k = 0; k < cnt; k++){ if (gray[k] && !used2[k]){ used2[k] = true; bool blue = false; queue<int> Q; Q.push(k); vector<int> cc; while (!Q.empty()){ int v = Q.front(); Q.pop(); cc.push_back(v); for (int w : E2[v]){ if (gray[w] && !used2[w]){ used2[w] = true; Q.push(w); } else if (is_path1[w]){ blue = true; } } } if (!blue){ for (int v : cc){ re[v] = true; } } } } for (int k = 0; k < cnt; k++){ if (re[k]){ E2[k].clear(); } else { vector<int> tmp; for (int v : E2[k]){ if (!re[v]){ tmp.push_back(v); } } E2[k] = tmp; } } swap(path[0], path[1]); } vector<int> type(cnt, -1); for (int v : path[0]){ type[v] = 0; } for (int v : path[1]){ type[v] = 1; } type[s] = 2; type[t] = 2; int cnt0 = path[0].size(); vector<int> pos0(cnt, -1); for (int j = 0; j < cnt0; j++){ pos0[path[0][j]] = j; } int cnt1 = path[1].size(); vector<int> pos1(cnt, -1); for (int j = 0; j < cnt1; j++){ pos1[path[1][j]] = j; } vector<pair<int, int>> E3; vector<bool> used(cnt, false); for (int j = 0; j < cnt; j++){ if (!used[j] && type[j] == -1){ used[j] = true; vector<int> id; vector<int> p0, p1; queue<int> Q; Q.push(j); while (!Q.empty()){ int v = Q.front(); Q.pop(); id.push_back(v); for (int w : E2[v]){ if (!used[w] && type[w] == -1){ used[w] = true; Q.push(w); } else if (type[w] == 0){ p0.push_back(w); } else if (type[w] == 1){ p1.push_back(w); } else if (type[w] == 2){ p0.push_back(w); p1.push_back(w); } } } for (int v : p0){ for (int w : p1){ E3.push_back(make_pair(pos0[v], pos1[w])); } } } } vector<int> mx1(cnt0, cnt1 - 2); vector<int> mn1(cnt0, 1); vector<int> mx2(cnt1, cnt0 - 2); vector<int> mn2(cnt1, 1); for (pair<int, int> P : E3){ int u = P.first; int v = P.second; if (u > 0){ mx1[u - 1] = min(mx1[u - 1], v); } if (u < cnt0 - 1){ mn1[u + 1] = max(mn1[u + 1], v); } if (v > 0){ mx2[v - 1] = min(mx2[v - 1], u); } if (v < cnt1 - 1){ mn2[v + 1] = max(mn2[v + 1], u); } } for (int j = cnt0 - 2; j >= 0; j--){ mx1[j] = min(mx1[j], mx1[j + 1]); } for (int j = 0; j < cnt0 - 1; j++){ mn1[j + 1] = max(mn1[j + 1], mn1[j]); } for (int j = cnt1 - 2; j >= 0; j--){ mx2[j] = min(mx2[j], mx2[j + 1]); } for (int j = 0; j < cnt1 - 1; j++){ mn2[j + 1] = max(mn2[j + 1], mn2[j]); } for (int j = 1; j < cnt0 - 1; j++){ ans[id2[path[0][j]]] += max(0, mx1[j] - mn1[j] + 1); } for (int j = 1; j < cnt1 - 1; j++){ ans[id2[path[1][j]]] += max(0, mx2[j] - mn2[j] + 1); } } for (int i = 1; i < N - 1; i++){ ans[i] += art_cnt; if (is_art[i]){ ans[i] = N - 3; } } } for (int i = 1; i < N - 1; i++){ cout << ans[i]; if (i < N - 2){ cout << ' '; } } cout << endl; }
未来の AtCoder
日時 | 出来事 |
---|---|
2038/01/09 12:14 | practice contest が終了する。 |
2728/05/29 22:44 | AtCoder Library Practice Contest の順位表が凍結される。 |
3020/02/29 21:00 | AGC042 が開始する。 |
3020/03/01 01:00 | AGC042 が終了する。 |
3020/09/27 22:31 | AtCoder Library Practice Contest が終了する。 |
3021/12/17 02:00 | アルゴリズムと数学 演習問題集 が終了する。 |
3030/10/03 21:00 | ACL Contest 2 が開始する。 |
3030/10/03 23:30 | ACL Contest 2 が終了する。 |
4017/12/13 21:00 | APG4b が終了する。 |
4018/03/14 21:00 | AtCoder Beginners Selection が終了する。 |
5021/07/11 19:00 | 競プロ典型 90 問 が終了する。 |
Stage 6: Grand Prix of EDG (2021-11-14)
jコンテストページ
問題概要
問題 A: A Hero Named Magnus
実行時間制限: 1 秒 / メモリ制限: 512 Mb
( は奇数) 回試合を行うことを考える。 試合目から 試合目までは の確率で試合に勝ち、 試合目以降は必ず試合に勝てるとき、 回試合を行ったあと勝った試合が負けた試合より必ず多くなるようにするとき、 の最小値を求めよ。ただし、 個のテストケースが与えられるので、すべて答えよ。
入力は以下の制約を満たす。
問題 B: A Plus B Problem
実行時間制限: 3 秒 / メモリ制限: 512 Mb
縦 行、横 列に数字を表示する機械がある。 行目と 行目の数字は自由に変更することができるが、 行目の数字は常に 行目と 行目に表示された数字をそれぞれ 桁の整数として見たときのそれらの和の下 桁を表示する。
個のクエリが与えられる。 番目のクエリでは、整数 が与えられるので、 行目 列目の数字を に変更した後、 行目 列目に表示されている数字と表示される数字が変化した箇所の個数を出力せよ。
入力は以下の制約を満たす。
問題 C: AC Automaton
実行時間制限: 13 秒 / メモリ制限: 512 Mb
頂点 を根とする 頂点の根付き木が与えられる。頂点 の親は である。また、各頂点には文字 が書かれている。ただし、 は A
, C
, ?
のいずれかである。
個のクエリが与えられる。各クエリでは整数 と文字 が与えられるので、頂点 に書かれた文字を に変更せよ。次に、?
が書かれた各頂点に書かれた文字を A
または C
に変更したとき、頂点 が頂点 の先祖で頂点 にそれぞれ A
, C
が書かれているような頂点の組 の個数の最大値を求めよ。ただし、この変更は実際は行わないものとする。
入力は以下の制約を満たす。
- は
A
,C
,?
のいずれかである。
問題 D: Assumption is All You Need
実行時間制限: 1 秒 / メモリ制限: 512 Mb
長さ の順列 が与えられる。 に以下の操作を繰り返して に変換する手順を示すか、そのような手順が存在しないことを報告せよ。
- なる整数 を選び、 と を交換する。
ただし、 個のテストケースが与えられるので、すべて答えよ。
入力は以下の制約を満たす。
- すべてのテストケースに対する の和は 以下である。
問題 E: Buy and Delete
実行時間制限: 2 秒 / メモリ制限: 512 Mb
頂点の有向グラフ がある。最初、 に辺はない。
アリスとボブがゲームを行う。アリスは ドルを持っていて、 種類の辺を買うことができる。 番目の辺は ドルであり、買うと の頂点 から頂点 に有向辺が張られる。その後、ボブは以下の操作を繰り返し を辺がない状態にする。
- の辺の部分集合 であって閉路を含まないものを選び、 に属する辺をすべて削除する。
ボブは操作の回数を最大化しようとし、アリスは操作の回数を最小化しようとするとき、ボブが操作を行う回数を求めよ。
入力は以下の制約を満たす。
問題 F: Illuminations II
実行時間制限: 2 秒 / メモリ制限: 512 Mb
二つの凸多角形があり、一方はもう一方の内部に完全に含まれている。外側の凸多角形は 角形、内側の凸多角形は 角形である。
外側の凸多角形の辺上のランダムな点にライトを設置するとき、内側の凸多角形の辺のうちライトで照らされる部分の長さの期待値を求めよ。
想定解答との絶対誤差または相対誤差が 以下であれば正解として扱われる。
入力は以下の制約を満たす。
- 頂点の座標は整数で絶対値が 以下である。
問題 G: Occupy The Cities
実行時間制限: 1 秒 / メモリ制限: 512 Mb
個の都市が一直線上に順番に並んでいて、そのうち 個以上は占領されている。長さ の文字列 が与えられ、 の 文字目が 1
のときは都市 が最初に占領されていること、`0
のときは都市 が最初に占領されていないことを示す。
以下の操作を繰り返し、すべての都市を占領された状態にしたい。
- 占領されているそれぞれの都市が、隣接する占領されていない都市を つまで選び、その都市を占領された状態にする。
操作の最小回数を求めよ。ただし、 個のテストケースが与えられるので、すべて答えよ。
入力は以下の制約を満たす。
- すべてのテストケースに対する の和は 以下である。
- は
0
と1
のみからなる長さ の文字列である。 - には
1
が つ以上含まれる。
問題 H: Popcount Words
実行時間制限: 1 秒 / メモリ制限: 512 Mb
区間 に対し、文字列 を以下のように定義する。
- である。ただし、 は を 進数で表したときの の個数が偶数ならば
0
、奇数ならば1
である。
個の区間 が与えられる。 とする。ただし、 は文字列の連結を表す。
個のクエリが与えられる。各クエリでは文字列 が与えられるので、 のうち が部分文字列として出現する回数を出力せよ。
入力は以下の制約を満たす。
- は
0
と1
のみからなる。 - すべてのクエリに対する の長さの和は 以下である。
問題 I: PTSD
実行時間制限: 1 秒 / メモリ制限: 512 Mb
人の人 がいる。 文字の 0
または 1
からなる文字列 が与えられ、 の 文字目が 1
のときは人 が PTSD を持っていること、0
のときは持っていないことを示す。
人を何個かのグループに分けるとき、各グループのうち 番目に番号が大きい人で PTSD を持っている人の番号の総和としてありうる最大値を求めよ。ただし、 個のテストケースが与えられるので、すべて答えよ。
入力は以下の制約を満たす。
- すべてのテストケースに対する の和は 以下である。
- は
0
と1
のみからなる長さ の文字列である。 - には
1
が つ以上含まれる。
問題 J: Suffix Automaton
実行時間制限: 6 秒 / メモリ制限: 512 Mb
文字列 のすべての異なる部分文字列を長さの昇順にソートし、同じ長さのものは辞書順に並べた列を とする。
個のクエリが与えられる。各クエリでは整数 が与えられるので、 の 番目の文字列が に現れる最も左側の区間の左端と右端の位置を求めよ。ただし、 が の長さより大きい場合は、-1 -1
と出力せよ。
入力は以下の制約を満たす。
問題 K: Tax
実行時間制限: 2 秒 / メモリ制限: 512 Mb
個の都市があり、 本の道路で結ばれている。道路を用いてどの つの都市の間も行き来することができる。 番目の道路は都市 と都市 を結び、会社 によって管理されている。また、長さ の整数の列 が与えられ、会社 が管理している道路を 回目に通るときは ドルを支払う必要がある。 のそれぞれに対し、都市 から都市 へ行くときに最小で何ドル必要か求めよ。
入力は以下の制約を満たす。
- どの つの都市も 本以下の道路で結ばれている。
- 道路を用いてどの つの都市の間も行き来することができる。
問題 L: Wiring Engineering
実行時間制限: 8 秒 / メモリ制限: 512 Mb
個のビルがあり、 番目のビルは座標 にある。また、 個の通信塔があり、 番目の通信塔は座標 にある。
個のクエリが与えられる。 番目のクエリでは、整数 が与えられるとき、区間 のビルと の通信塔の間に以下の条件を満たすように何本かの電線を張ったとき、最大何ドル得られるか求めよ。
- ビル と通信塔 を電線で結ぶと ドルが得られる。ただし、電線はビル と通信塔 を結ぶ線分である。
- ビル に 本以上の電線を張るとき、 ドルを支払う。
- 通信塔 に 本以上の電線を張るとき、 ドルを支払う。
- 本以上の電線がその端点以外で交わってはならない。
入力は以下の制約を満たす。
問題文
問題 A: A Hero Named Magnus
https://official.contest.yandex.ru/opencupXXII/contest/31241/problems/A/
問題 B: A Plus B Problem
https://official.contest.yandex.ru/opencupXXII/contest/31241/problems/B/
問題 C: AC Automaton
https://official.contest.yandex.ru/opencupXXII/contest/31241/problems/C/
問題 D: Assumption is All You Need
https://official.contest.yandex.ru/opencupXXII/contest/31241/problems/D/
問題 E: Buy and Delete
https://official.contest.yandex.ru/opencupXXII/contest/31241/problems/E/
問題 F: Illuminations II
https://official.contest.yandex.ru/opencupXXII/contest/31241/problems/F/
問題 G: Occupy The Cities
https://official.contest.yandex.ru/opencupXXII/contest/31241/problems/G/
問題 H: Popcount Words
https://official.contest.yandex.ru/opencupXXII/contest/31241/problems/H/
問題 I: PTSD
https://official.contest.yandex.ru/opencupXXII/contest/31241/problems/I/
問題 J: Suffix Automaton
https://official.contest.yandex.ru/opencupXXII/contest/31241/problems/J/
問題 K: Tax
https://official.contest.yandex.ru/opencupXXII/contest/31241/problems/K/
問題 L: Wiring Engineering
https://official.contest.yandex.ru/opencupXXII/contest/31241/problems/L/
Stage 5: Grand Prix of Siberia (2021-11-07)
コンテストページ
問題概要
問題 1: Polesov and Work
実行時間制限: 3 秒 / メモリ制限: 256 Mb
整数 と正の整数 が与えられる。円 内の格子点 に対し、 の最大値を求めよ。ただし、 個のテストケースが与えられるので、すべて答えよ。
入力は以下の制約を満たす。
問題 2: Orienteering
実行時間制限: 5 秒 / メモリ制限: 256 Mb
座標平面上に 個のチェックポイントがあり、 番目のチェックポイントは点 にある。それぞれのチェックポイントは、その位置から距離 以内の点を訪れたとき、通過したとみなす。
座標平面上の任意の点から開始し、 個のチェックポイントを順に通過したい。ただし、途中で他のチェックポイントを通過してもよいが、それらは通過したとみなさない。このとき、移動距離の最小値を求めよ。
想定解答との絶対誤差または相対誤差が 以下であれば正解として扱われる。
入力は以下の制約を満たす。
問題 3: Dice
実行時間制限: 2 秒 / メモリ制限: 256 Mb
それぞれの面に と書かれた 個の面があるサイコロが 個ある。これらのサイコロを振り、出た目の数の合計を計算し、さらに を加算した。結果が となることがあか判定せよ。ただし、 個のテストケースが与えられるので、すべて答えよ。
入力は以下の制約を満たす。
問題 4: Numeral Systems
実行時間制限: 3 秒 / メモリ制限: 256 Mb
先頭が でない数字のみからなる 文字の文字列であって、 進数として見たときの値を 、 進数として見たときの値を としたとき、 であり が で割り切れるようなものを、昇順にすべて列挙せよ。ただし、 個のテストケースが与えられるので、すべて答えよ。
入力は以下の制約を満たす。
問題 5: Hockey
実行時間制限: 1 秒 / メモリ制限: 256 Mb
ゴールキーパーを除き各チーム 人で 分間ホッケーの試合をする。
試合を行っているそれぞれの選手は、ペナルティを受けることがある。ペナルティにはマイナーペナルティとメジャーペナルティの 種類があり、ペナルティを受けた選手はそれぞれ 分間試合から外れる。また、一方のチームが相手のチームより試合を行っている人数が少なく、相手のチームがゴールをした場合、そのチームにマイナーペナルティにより試合から外れている選手がいれば、それらのうち最も早くにペナルティを受けた選手 人が試合に戻る。
分間の間に発生したゴールとペナルティの情報が時間の順に 秒の位まで 個与えられる。ただし、ゴールが発生した時刻の 秒の位は必ず 以外であり、ペナルティが発生した時刻の 秒の位は必ず であることが保証される。
試合中のある時点について、二つのチームで試合を行っている選手の人数がそれぞれ 人、 人であるとき、試合の形式が 対 であるという。 分間でそれぞれの試合形式が発生していた期間の長さを、一度以上発生した試合形式それぞれについて出力せよ。出力の順番は問わない。ただし、少なくとも一方のチームで試合を行っている選手の人数が 人未満だった期間が必ず存在することが保証される。
入力は以下の制約を満たす。
問題 6: Days of The Week
実行時間制限: 1 秒 / メモリ制限: 256 Mb
個の宇宙があり、それぞれの宇宙には つの曜日 (月曜日、火曜日、水曜日、木曜日、金曜日、土曜日、日曜日のうちの つ) が定められている。それぞれの宇宙の現在の曜日が与えられる。
個のスイッチがある。それぞれのスイッチにはある宇宙の集合が対応しており、そのスイッチを押すとそれらの宇宙の曜日がそれぞれ 日分進む。スイッチは任意の順番で何度でも押すことができる。
各宇宙の曜日の組み合わせ 個のうち、スイッチを何度か押すことで作ることのできないものが存在するか判定せよ。存在しない場合は NO
と出力し、存在する場合は YES
と出力した後そのような組み合わせを つ出力せよ。ただし、 個のテストケースが与えられるので、すべて答えよ。
入力は以下の制約を満たす。
問題 7: Balls
実行時間制限: 3 秒 / メモリ制限: 255 Mb
青玉と赤玉をそれぞれ何個か用意し、アリスとボブがゲームを行う。
アリスから始めて、 人が交互に玉を つ取る。ただし、アリスは残っている玉すべてを等確率で取り、ボブは必ず赤玉 つを取る。また、どちらの手番であるかに関わらず、残っている青玉が 個になったらアリスが勝ち、残っている青玉の個数が赤玉の個数より多くなったらボブが勝つ。
ゲームを 回行う。それぞれのゲームでは、青玉と赤玉の合計個数 が指定されるので、アリスが勝つ確率と の差の絶対値がなるべく小さくなるように青玉と赤玉を用意したい。このとき、用意すべき青玉の個数を出力せよ。
入力は以下の制約を満たす。
問題 8: Romualdych and Remainders
実行時間制限: 2 秒 / メモリ制限: 256 Mb
整数 が与えられる。 を満たす整数の組 が存在するか判定せよ。存在しない場合は -1 -1
と出力し、存在する場合はそのような組み合わせのうち が最も小さいものを つ出力せよ。ただし、 個のテストケースが与えられるので、すべて答えよ。
入力は以下の制約を満たす。
問題 9: Polynomials
実行時間制限: 3 秒 / メモリ制限: 256 Mb
黒板の左側に 個の多項式が、右側に 個の多項式が書かれている。各多項式の次数 と係数 が与えられる。
黒板の右側に書かれているそれぞれの多項式について、黒板の左側に書かれている多項式を つ選び、以下の 種類の操作を繰り返し適用してその多項式と一致するようにするときの、操作回数の最小値を求めよ。
ただし、操作は黒板の右側に書かれているそれぞれの多項式について独立して考えるものとする。
入力は以下の制約を満たす。
問題 10: Find The Vault
実行時間制限: 6 秒・15 秒 / メモリ制限: 512 Mb
の #
, .
, _
からなるグリッド ( とする) と の #
, .
, _
からなるグリッド ( とする) が与えられる。 の の部分長方形であって、その各マスが以下の条件を満たすものを全て列挙し、それぞれの左上のマスの位置を出力せよ。
- そのマスに対応する のマスが
#
であるならば、その のマスは.
ではない。 - そのマスに対応する のマスが
.
であるならば、その のマスは#
ではない。
入力は以下の制約を満たす。
問題 11: Captivating Process
実行時間制限: 4 秒 / メモリ制限: 512 Mb
長さ の数列 が与えられる。 個のクエリが与えられるので、すべて答えよ。
各クエリでは 以上 以下の整数 が与えられ、以下の操作を繰り返す。
- ならば操作を終了する。
- そうでないならば、 を で、 を で置き換える。
操作が有限回の繰り返しで終了するなら YES
、そうでないなら NO
と出力せよ。
入力は以下の制約を満たす。
問題文
問題 1: Polesov and Work
https://official.contest.yandex.ru/opencupXXII/contest/31145/problems/1/
問題 2: Orienteering
https://official.contest.yandex.ru/opencupXXII/contest/31145/problems/2/
問題 3: Dice
https://official.contest.yandex.ru/opencupXXII/contest/31145/problems/3/
問題 4: Numeral Systems
https://official.contest.yandex.ru/opencupXXII/contest/31145/problems/4/
問題 5: Hockey
https://official.contest.yandex.ru/opencupXXII/contest/31145/problems/5/
問題 6: Days of The Week
https://official.contest.yandex.ru/opencupXXII/contest/31145/problems/6/
問題 7: Balls
https://official.contest.yandex.ru/opencupXXII/contest/31145/problems/7/
問題 8: Romualdych and Remainders
https://official.contest.yandex.ru/opencupXXII/contest/31145/problems/8/
問題 9: Polynomials
https://official.contest.yandex.ru/opencupXXII/contest/31145/problems/9/
問題 10: Find The Vault
https://official.contest.yandex.ru/opencupXXII/contest/31145/problems/10/
問題 11: Captivating Process
https://official.contest.yandex.ru/opencupXXII/contest/31145/problems/11/
ABC226 G: The baggage
公式解説とは異なる解法で解きました。
解法
荷物の重さの合計が体力の合計より大きいとき答えは明らかに No
なので、以後、荷物の重さの合計は体力の合計以下であるとします。このとき、重さ 以上の荷物をすべて割り当てることができれば、重さ の荷物も必ず割り当てられるので、重さ 以上の荷物のみ考えます。
仮に重さ 以上の荷物がないと仮定すると、割り当てられる重さ の荷物の個数は最大で 個となります。この値を とおくと、重さ の荷物を割り当てることができるためには となればよいので、重さ 以上の荷物を加えていったときの の値を最大化すること、つまり の値の減少量を最小化することを考えます。
重さ 以上の荷物は 人につき 個しか持つことができません。重さ の荷物が体力 または の人に割り当てられたとき は 減少し、重さ の荷物が体力 の人に割り当てられたとき、また、重さ 以上の荷物がそれ以上の体力の人に割り当てられたとき、 は 減少します。よって、 の減少量の最小値は以下のように求めることができます。
- の 頂点からなる有向グラフを考え、以下のように辺を張ります。
- 頂点 から にそれぞれ容量 、コスト の辺を張る。
- 頂点 から と にそれぞれ容量 、コスト の辺を張る。
- 頂点 から 、 から 、 から 、 から にそれぞれ容量 、コスト の辺を張る。
- 頂点 から にそれぞれ容量 、コスト の辺を張る。
- このグラフ上で頂点 から に最小費用流を流します。流量が に等しい場合 の減少量の最小値はコストの合計値に等しく、満たない場合割り当ては不可能です。
実装
#include <bits/stdc++.h> #include <atcoder/mincostflow> using namespace std; using namespace atcoder; const long long INF = 1000000000000000000; int main(){ int T; cin >> T; for (int i = 0; i < T; i++){ vector<long long> A(6); for (int j = 1; j <= 5; j++){ cin >> A[j]; } vector<long long> B(6); for (int j = 1; j <= 5; j++){ cin >> B[j]; } long long SA = A[1] + A[2] * 2 + A[3] * 3 + A[4] * 4 + A[5] * 5; long long SB = B[1] + B[2] * 2 + B[3] * 3 + B[4] * 4 + B[5] * 5; if (SA > SB){ cout << "No" << endl; } else { long long cnt = B[2] + B[3] + B[4] * 2 + B[5] * 2; mcf_graph<long long, long long> G(8); G.add_edge(0, 1, A[3], 0); G.add_edge(0, 2, A[4], 0); G.add_edge(0, 3, A[5], 0); G.add_edge(1, 4, INF, 1); G.add_edge(1, 5, INF, 2); G.add_edge(1, 6, INF, 1); G.add_edge(2, 5, INF, 2); G.add_edge(2, 6, INF, 2); G.add_edge(3, 6, INF, 2); G.add_edge(4, 7, B[3], 0); G.add_edge(5, 7, B[4], 0); G.add_edge(6, 7, B[5], 0); pair<long long, long long> F = G.flow(0, 7); if (F.first < A[3] + A[4] + A[5]){ cout << "No" << endl; } else { cnt -= F.second; if (A[2] > cnt){ cout << "No" << endl; } else { cout << "Yes" << endl; } } } } }
ICPC 参加記ではありません
のいみさんが言っていたので
誰か参加記まとめて
— のいみ (@noimi_kyopro) 2021年11月6日
https://twitter.com/season1618/status/1456599426705682437 https://twitter.com/mugen_1337/status/1456609488832655366 https://twitter.com/noimi_kyopro/status/1456617930708320258 https://twitter.com/tatyam_prime/status/1456633955147399179 https://twitter.com/harurun_p/status/1456638710208888839 https://twitter.com/totori_kpr/status/1456639772336660493 https://twitter.com/kuma_program/status/1456648584237969412 https://twitter.com/tko919_/status/1456649097922838533 https://twitter.com/suta28407928/status/1456652006358065160 https://twitter.com/packer_jp/status/1456653046943862788 https://twitter.com/_KKT89/status/1456653275688693761 https://twitter.com/sotasingularity/status/1456654907415564289 https://twitter.com/noss46/status/1456657522241146884 https://twitter.com/polyester_CTRL/status/1456664517174198274 https://twitter.com/emtsu_ba/status/1456682116037500934 https://twitter.com/_rniya_/status/1456686229945143299 https://twitter.com/kari_math/status/1456712491715555329 https://twitter.com/sapphire__15/status/1456727775356723200 https://twitter.com/Enjapma_kyopro/status/1456776327193776132 https://twitter.com/Div9851/status/1456785163984113673 https://twitter.com/shiro537/status/1456785393802616834 https://twitter.com/heno_code/status/1456795950232399872 https://twitter.com/wakuwinmail/status/1456816914806689793 https://twitter.com/myau_atcoder/status/1456827886057361413 https://twitter.com/cloudman_P/status/1456855164355186690 https://twitter.com/eiya5498513/status/1456856801702412293 https://twitter.com/HIR180/status/1456875628280500230 https://twitter.com/Motsu_xe/status/1456904394864164864 https://twitter.com/chomonolis/status/1456932057016274948 https://twitter.com/Enjapma_kyopro/status/1456940619461378049 https://twitter.com/ynu_cpc/status/1456961602943479808 https://twitter.com/kotatsugame_t/status/1457486047122579459 その他 https://twitter.com/rian_tkb/status/1456901256178388999