ABC344

5完水パフォ。ゴミ。

A - Spoiler

'|'が来るたびに状態をflipして、答えのstringに入れるかどうか決める。'|'を入れないようにするのどう実装するか悩んだが、'|'かどうかで場合分けすればよかった。

B - Delimiter

入力がそこで終わってるかどうかはA_iが0かどうかで判定できる。問題文に書いてあるけど、そこに気づくのが一番難しい。

C - A+B+C

屈辱のunordered_set。bitsetでやれば速いとわかっているが、早くACを得るためにunordered_setを使う。終了後に試したら、メモリ使用量すらbitsetのがよかった。このくらいならコンテスト中でもやったほうがいい
か(気分は大切)。unordered_setを使ったコードの実行時間が思ったより長かったが、出力が多いのを忘れてIO高速化してなかったからだった。

D - String Bags

全然見えないけどさすがにDPだろうと思ってやっていくと実際にDPできる。計算量も余裕がある。「何もしない」があるのを、知ってはいるんだけどなんか忘れてサンプルが合わなかった。DPの更新が大量に入るので、同じ袋の文字列を2回使ったりする遷移が本当にないか自信が持てなかった。提出したらACだったけど。

E - Insert or Erase

双方向リストでできる。std::listは、使った経験がほとんどないし、64bitのイテレータを扱うよりは自前の32bitインデックスでいいだろみたいな感じで自前実装。値と前後のインデックスを持つ。リストの構造体のvectorを最初にN個作って、新たな要素の追加でそこへpush_backしていく。何がどのインデックスにあるかはunordered_mapで持つ。これは、消すときは放置。リストのほうは、消したら-2で埋める。前のインデックスを-1にすることで唯一の先頭の印とするため。あとは普通にリストの処理を書く。サンプルがなかなか合わなかったが、なんと出力で間違えていた。リストを辿ってインデックスを更新したあとでアクセスしてて普通にバグ。直したらACできてよかった。

こういうの飛ばすかどうか難しい。

解説を見て、番兵使うのは思いつかなかったなあ。

F - Earn to Advance

Eに時間がかかったとはいえ、40分以上残っている。だが、一つの方針の検討に20分かかっていては2つ検討してコンテストが終わる(2つ目が当たりだったとして実装時間がない)。最初に最小費用流を考えてしまったが、それで解けるか以前によく考えたら(実行時間が)間に合うわけがない。次に正面から考えて、経路を固定すると最もPが大きいマスを更新していきそこで稼いだことにすればいいとわかる。後ろから見たらどうか、前から見たらどうか、色々景色が違って難しい。最大マスも持って4乗DPとしても、半端のお金の扱いが不可能。

(追記)あとから稼いだことにするんだから、あまったお金はそこまでの最大マスのPより少ない。言われてみればそうだが、ちゃんと理解できてる気がしないなあ。自分の理解が間違っていれば、間違いを見つけることで理解が進むが、これは正しいのだからどうしようもない。貰うDPで書き始めるが、どこに貰うかは最大値が更新されるかで変わるので結局は配る感じにもなる。メモリ制限ギリギリの巨大DPテーブルなのであまりしたくはなかったが最初から全部初期化した(ローカルでは200ms以上かかる)。移動するとき、あまってるお金で足りなくなったらその分を最大マスで稼ぐ(ここで割り算が必要)。その後、最大値が更新されるかで遷移先を決めて更新。いやあ難しい。書いてしまえば見通しも立つが、最初は全然見えなかった。これはDPが苦手なのか、別のものが苦手なのか。