ABC177

5完。早解きができないのは仕方ない。Fが惜しいところまでも行かないのが、はっきりとした力不足を感じさせる。「単に競プロ飽きたからFを考えるのがしんどかった」という説もあり、それならまあいいんだけど(その場合は競プロをよりゆるく続ければいい)。他には、今月は色々あったのでまだ心が回復していないという可能性もある。それ以外だとすると、この種の思考力が落ちてそうで、今後の人生が不便そうで嫌だ。

開始直前にトイレに行って、Aをやっているときにまた行きたくなったので、Aを通したら急いでBCDを開きその中からDを読んでトイレへ行った。すぐ解けたので、戻ってきてDを通してからBCをやった。

A - Don't be late

難しそうな見た目をしている。かかる時間を計算すると整数だけで済まない。でもよく考えるとT分で移動できる距離を求めればいい。サンプル2がピッタリ間に合うケースで、しかも2000=20*100という形をしているので、正しさの確認になる。

B - Substring

パッと見のわけわからなさではCやDより上だった。よく考えると、部分文字列の開始位置を全探索するだけだった。

C - Sum of product of pairs

よくあるやつ。厄介ポイントがあるとすれば i < j という条件だが、自分より前に出てくるやつと積をとればいいので、そこまでの和を更新しつつそれと自分の積を足していけばいい。正方形の左下を埋めていくイメージ。

D - Friends

ここでいう「友達」は同値関係なので、UnionFindで同値類に分ける。「同じグループの中に友達がいない」ようにするには、一番大きい友達集合の人数と同じ数のグループが必要。そして、その数のグループがあれば各友達集合をバラバラに分配できる。

E - Coprime

よくわからん英語が出てきて読むのに時間がかかる。内容自体は自分が持っている概念だったので、単に言葉の問題。全体のGCDが1かどうかは単に計算すればいい。問題は、どの2個をとってもGCDが1(互いに素)かの判定。ある素因数、例えば3に注目して、3の倍数が2個以上あったらダメ。A_i <= 10^6 なので、それ以下の全ての素数について被りがなければOK。とりあえず線形篩を貼っておけばいいかな。入力が100万個もあるのでlog1個付けるくらいしか許されなさそう。std::setを使うことも考えたが、高々10^6だからstd::vectorでいい。A_iが1のときは(誰とでも互いに素なので)どうでもよくて、そうじゃないときは素因数を一つとって(これは篩で計算済み)これまでに現れてないかチェックしてから割っていき1になったら抜ける。

けっこうバグらせた。1になったら抜けるのではなく素数になったら抜けるようにしてて素数の2乗とかで死ぬと気づいたり。割れる限り割らないと自分同士で被りを検出してしまったり。なんか答えが3通りあるのが多くて混乱してしまった。特に難しいところはないと思ったけど、最初の段階で最終的な実装を想像することは全くできていなかったので、やはり自分にとってはある程度難しかったのかなあ。

F - I hate Shortest Path Problem

↓考察コメント貼っとく。途中でstd::set(増えたり減ったりするので計算量が全然わからん)で上手いことできないかとかも考えたが、最終的にはずっと遅延セグ木でどうしたら書けるかを考えてた。遅延セグ木の理解の浅さが出た部分もある。まあそれはよくて、コンテスト中にしっかり考えられなかったことのほうが気になる。よく見たら問題名なんだこれ。

//右への移動は、後回しにしてよさそう つまり、ムーブとしては下がれるなら下がる、そうでないならBまで移動
//とすると、-1かどうかは左上隅からのスタートでできるかでわかる これはシミュレーションできる
//問題は、どこからスタートするのが最短になるか 言い換えれば右への移動回数
//あと1つ右からスタートしてれば最適解だったのにという状況のとき、無意味に右移動1回入る
//あと1つ左からスタートしてれば最適解だったのにという状況のとき、どこかでAに引っかかってる
//そもそもH回移動する最短だけ求めるのでもどうしたらいいんだ?
//ていうかこれ最終的に何がわかるんだ 遅延セグ木でシミュレーションか?二分探索できる?