ABC226

5完。時間かかるし未証明ACするしでいいとこなし。何か失敗したわけではないが、全体的にパフォーマンスが低い。薄く落ち込んでいる。

A - Round decimals

文字列として受け取ってから、桁数が一定ではないことに気づいた。仕方ないので、小数点が来るまでは普通に整数を求めて、その後は「'5'以上なら1を足す」をしてすぐループを抜ける。3分以上かかってる。

誤差はどうだったかなあ。0.499を誤判定することはない。問題は0.500で、これが内部でわずかに小さくなったりするのが心配だったが大丈夫じゃんこれ0.5はdoubleで正確に表せるよ。このくらいすぐ気づきたいが。しかも、多少ずれるとしてさえ(例えば零捨一入しろという問題でも)1e-9とかを足してから丸める(改めて0.5を足して切り捨てる)ことで正解できる。頭に考える部分が付いてなくて酷い。

B - Counting Arrays

クソムズ。vector<basic_string<int>>で受け取ってstd::uniqueした。こういうソートの計算量がO(N*log(N))なのは知っていたので(理由を説明できないところがゴミクズ)。つーかvector<int>がそもそも大小比較できるんだ。聞いたことはあったかもしれないがちゃんとは知らなかったよ。

C - Martial artist

難しすぎると思ったけど後ろから考えればいい。技Nの習得にはこれが必要、そのためにはこれも必要、とやっていくと、それらは全部必要だしそれで十分。実装は、後ろから依存関係をpriority_queueに入れていった。今考えると、配列にメモしていくだけでいい。はー。

D - Teleportation

整数の組であることが影響するか?直線上にある複数の点に対する答えは2でいいか?証明が浮かばず、反例が見つかりそうにないので、それで実装した。全ての2点についてベクトルを互いに素になるようにxが負にならないようにxが0ならyが負にならないように正規化してstd::setで数える。2倍して出力。

(解説を見て)あーこれは明快。言われてみれば、点iから点jへは移動しなければならないのだからそのための魔法は覚える必要があり、その整数の組は互いに素になるように割って損しない。約数は全てこいつの倍数なんだなあ。

E - Just one

連結成分毎に掛ければいい。以下、連結グラフで考える。向きを逆にしても答えは同じだが、そうしたほうが楽かなーとか考えたせいで後々少し混乱した。ループがあるとその部分は2通り。けっこうな時間手で実験をしていた。どうも、なもりグラフなら2通りで他は0通りっぽい。木がなぜダメかを考えると、出次数が全部1だから入次数の合計はN(頂点数)で無向辺の個数はNでなければならない。ループに関してはよくわからんけど、一つのループに注目しそこの向きを決めたら外からは入ってくるしかないので木しか生えなさそう。

(解説を見て)あー辺数Nってわかってるんだから木のときと同様に考えてループは1個だけじゃん。次からサイクルって言います。

F - Score of Permutations

何もわからないので例を手で試す。だんだん意味がわかってくる。スコアは、周期だ。2 1 3 4 5みたいな順列だったら、一致している部分は動かない。最初「巡回群」でググっていた。順列を置換と捉え巡回置換に分解する、ということだと思うけど、コンテスト中はもっとうんと低い解像度で考えていた。プログラムを書いて実験すると、分解してi個の塊があったとしてその周期はちょうどiになるっぽい(分解できないものが巡回になっている確信が持てなかった)。一致しているところも、周期1と見ることができる。ということで、ある順列のスコアは、分解してそのサイズたちの最小公倍数。これでとっかかりはできた(コンテスト中ヒマになることはなくなった)。Nが小さいので、分解の仕方を全列挙できないかDFSを書いて確認してみる。大きいものから取っていき、同じサイズはまとめて取る(広義単調減少で和が50になる正整数列を列挙)。やってみると何十万とかなので、これでいけるかも。残り個数とサイズの最大値と最小公倍数と通り数を持ってDFS。N個からi個選んで、同じサイズをj回選ぶときはjの階乗で割る(例えば選んだ一番左の位置でソートして正規化)。残り5分でサンプルが合わない。ACしたのは終了22分後だった。

まず全体の通り数がNの階乗になっている必要がある。それを確認するために末端で通り数を足していく。デバッグ中これがたまたま合うこともあり、また、通り数ではなく1を足していたこともあり、ズタボロ。N個からi個選んでiの階乗通りの並べ替えがあると思っていたが、一致したらダメじゃんと気づいて撹乱順列に行った。それでもサンプルは合わず、しつこく考えると撹乱順列は分解されることもあった。そういうのも包除で取り除くのは大変そうだなあと思ってしまったが、正面から考えるとただの階乗になって簡単だった(酷い)。巡回になっているのが何通りかを考えると、1個ずつ行き先を決めていくだけ。実装でも、変数の宣言場所を間違えて壊れていたりした。

(解説を見て)よく読んでないけどあーこれ分割数という名前か。

G - The baggage

(追記)なんとか自力AC。だが複雑すぎてコンテスト中にこの方針で解くことは現実的でない。まずB1の人はA1を持つしかない。B2はA2を持つのが最善(例えばA1を2個持ったときと比べ荷物が分割されて状況が悪くならない)。次にA1を持たせる。B3はA3を持つのが最善。次に、A1A2を1個ずつ持つ(他の持ち方と比べると荷物が分割されたり軽くなったりするので不利にならない)。あとはA1かA2が残っているだけなので持てるだけ持つ。B4はA4を持つのが最善。A5の立場からすると持ってもらえるのはB5のみなので持ってもらう。これでA5は終わり。で、A4からするともうB5に持ってもらうしかない(さっきB4が持てるだけA4を持ったので)(ここでA1A4で持ってもらうケースを忘れて1WA(A4は持ってもらうしかなくてA1は持たせ得なので持たせる))。そうすると、A1A2A3B4B5だけが残る。ここで、B5はA2A3で持つのが最善(他のどんな持ち方よりもいい)。なので持てるだけ持たせて、これでA2A3B5のどれかが0になったので場合分け。B5がいなくなればB4だけで持つことになるので、A3の立場ではA1A3かA3で持ってもらうしかなく、残ったA1A2は(半端が出ないので)簡単。A2が0になったときは、A3は1人1個しか持てないのでA1で埋めながら持ってもらう。A3が0のときは、B5の立場ではA1A2A2で持つのが最善。その持ち方ができなくなったらA1A1A1A2。あまりのA1とA2は、B4が効率よく持てる。これで解けたはずだけど1箇所でも間違ってたら意味ないわけで、自信が持てない(実際WAを出したし)。ゆーて解説もけっこう複雑で、俺はこの問題から何を学べばよかったのかわからない。

(解説放送を見て)ビンパッキング問題というのか。自分は荷物は分割されていたほうがいいという考え方しかしていなかったが、ビンは分割されていないほうがいいというのもあった。荷物を持たせたら体力が減る扱いにすれば、1回に1個だけ持たせるようにできて楽だった。難しいのはA3をB4B5どちらに持たせるかという部分だった。