A - Large Digits
文字列として受け取って和をとったけど, 普通にやった方が良かったかも.
B - Gentle Pairs
浮動小数点数 (double
など) を使うと誤差が怖いので, 整数型演算だけで判定したい. 二点 , を結ぶ直線の傾きは, なので, かどうかが判定できれば OK. 分母を払えば整数演算のみで判定できるが, 符号に注意する必要がある. 方法としては, 次の二つが考えられる.
- の昇順に点をソートしておくことで, 常に の符号が一定になるようにする
C - 1-SAT
HashSet<String>
を用意して, を全て入れておく. その後, 各 に対して, の先頭に !
を付加した文字列が Set
に入っているかを確認し, 見つかればその を出力. 最後まで見つからなければ, satisfiable
を出力.
D - Choose Me
を管理する. 初め, である. となるように街で演説をしたい.
高橋氏が街 で演説したとき, 青木氏の票は だけ減り, 高橋氏の票は だけ増える. つまり, の値は だけ増える.
従って, の値が大きい順に貪欲に を選んでいくことを となるまで繰り返し, となった時点でそれまでに演説をした回数を出力すれば良い. なので, この操作は必ず終了する.
E - Through Path
部分木加算クエリが処理できれば良い. 適当に根を決めて深さ優先探索をする. このとき訪問順に頂点を記録していくと, 部分木は区間に対応する. 従って, この区間を各 に対して前計算をしておくと, 各クエリは遅延伝播セグメント木を使えば , imos 法を使えば で処理できる. imos 法を使うことにすると, 全体 でこの問題を解くことが出来る.
F - Close Group
グラフを複数のクリークに分割する問題. まず, の各部分集合 に対して, 以下のテーブルを埋めておく.
このテーブルは愚直に計算して で埋められる.
続いて, 次の DP テーブルを埋める.
このテーブルは, 以下のように埋められ, 元の問題の答えは である.
テーブルの更新では の部分集合を列挙する必要があるが, これは以下のようにすれば全体 で可能である.
for (int i = 0; i < 1 << n; i++) { // j ⊂ i, j != ∅, j != i なる j を無駄打ちなしで列挙する. for (int j = (i - 1) & i; j > 0; j = (j - 1) & i) { } }
外側の for
文が全体 で動作することは, 以下より従う.
以上より, 全体 でこの問題を解くことが出来る.