ABC 239
Table of Contents
A - Horizon
問題分通りの値を出力するだけ.
B - Integer Division
$X > 0$ のときは素直に整数除算 $X / 10$ を出力する.
$X < 0$ のとき, $X \equiv 0 \mod 10$ なら整数除算 $X / 10$ を出力し, $X % 10 \neq 0$ なら $X / 10 - 1$ を出力する.
void solve() {
ll x;
cin >> x;
if (x < 0 && x % 10 != 0) {
cout << x / 10 - 1 << endl;
} else {
cout << x / 10 << endl;
}
}
余談
午前中に勉強していた coursera の講義 Competitive Programmer’s Core Skills Week 3 の課題で $\lceil \frac{x}{y} \rceil$ を出力する問題があって, それを解いていたおかげで $x / y$ が負のときは場合分けが必要とわかっていたため比較的にすぐに解くことができた.
C - Knight Fork
注記の図に書いてある通りで, 格子点 $(x, y)$ からの距離が $\sqrt{5}$ になる格子点の座標は $(x+1, y+2)$, $(x+2, y+1)$, $(x+2, y-1)$, $(x+1, y-2)$, $(x-1, y-2)$, $(x-2, y-1)$, $(x-2, y+1)$, $(x-1, y+2)$ の8点である.
$(x_1, y_1)$ からの距離が $\sqrt{5}$ となる格子点の集合と,
$(x_2, y_2)$ からの距離が $\sqrt{5}$ となる格子点と集合に
共通要素があれば Yes
, そうでなければ No
を出力する.
D - Prime Sum Game
$A, B, C, D \leq 100$ と小さいので全探索する. 任意の高橋君が選んだ数字 $x$ に対して, 青木くんが常に素数を作ることができれば青木くんの勝ち. そうでなければ高橋君の勝ち.
素数判定のためにエラトステネスのふるいで素数判定配列を作っておくと楽だが, 愚直に $O(\sqrt{N})$ のアルゴリズムでの判定でも十分間に合う.
E - Subtree K-th Max
解説 AC
葉から各部分木に含まれる数の上位20個を配列に保存する. このとき, 配列は降順にソートしておく. 各クエリに対してノード $V$ の $K$ 番目を出力すれば良い.
vvint graph;
vint score;
vvint child;
const int MAX_KTH = 20;
void dfs(int x, int p) {
child[x].push_back(score[x]);
for (int nx : graph[x]) {
if (nx == p)
continue;
dfs(nx, x);
for (int i = 1; i <= min((int)child[nx].size(), MAX_KTH); i++) {
child[x].push_back(child[nx][i - 1]);
}
}
sort(rall(child[x]));
}
提出コードだと配列に上位20個でなく, $\text{子ノードの数} \times 20 + 1$ の数が入ってくるが $k-d$ tree の $k = 20$ みたいなものなので空間計算量も大したことないので問題ない(多分).
直感的には
- 各ノードの次数が低いとき
- 「木が高い」となるが, 長さ $20$ の配列が $O(N)$ 回くらい伝搬するので計算量は $O(20N)$ くらい,
- 各ノードの次数が高いとき
- 「気が低い」となり, $O(N)$ の操作は大した回数にならないだろうと想像できる.
最悪計算量が $N\log_{20}N$ くらいになりそうな気がするが証明はできていない.