PAST202104-OPEN

MNが解けなかった。いつもながらPASTはしんどい。今回特に多かったのは、簡単だけど実装がありえないほど複雑とか、解き方が見当もつかないとか。

A - POSTal Code

全部確かめる。

B - PASTal Code

4文字ステップで'o'を探す。ここまで簡単なのでうれしい。

C - 携帯電話の購入 / Buying a Cellphone

えらく複雑になってトイレ行きたくなった(後半を覗いて問題文が短いO問題を頭に入れてから行った)。ビット演算でやった。

D - K項足し算 / K Integers Summations

K回足して出力、残りをN-K回足し引きして出力。簡単だが、この回数のイメージがパッと出るか。

E - 前から3番目 / Third from Front

dequeの端以外を削除する計算量がわからなかったから毎回3つ削除して入れ直した。端に近いから大丈夫ということか。最初ABCDEF全部if文を書いてしまったが、さすがにまとめて処理。

F - 安全装置 / Safety System

地獄。明らかに簡単なのに、連続T秒になった瞬間に処理が終わるとかそういう"タイミング"を全て正しく書く必要がある。頼むもうこんなこと考えたくない通ってくれと思いながら死んだ頭で提出ボタンを押し、運良くAC。

G - 一日一歩 / One Step at a Time

BFSだと思って書くがサンプルが全然合わず、全然違う状況であることに気づく。日によって通れるかどうか変わるのでまともな計算量でできそうにない。全然わからないのであと回し。

ダイクストラ法でできると気づく。辺のコストが動的に決まっていくやつ。時間が距離という、めちゃんこイメージが難しいやつ。まあ処理自体はライブラリのダイクストラをちょっといじるだけ。問題は、その道が次に通れるようになるのがいつかを求める方法。セグ木二分探索でlog2つ(本来1つにできるやつ)。ダイクストラ法と合わせてlog3つ付けてしまったと思っていたが、辺は1回しか見ないから2つで済んでるか。

(解説を見て)うへえ。辺を管理するのか。頂点を毎回見たら間に合わないけど辺をpriority_queueに入れれば使えるやつ全部使うが高速にできる。いくらアルゴリズムの勉強したからってこれができないんじゃなあ。

H - カンカンマート / Can Can Mart

ちょっと面食らうけど、よく考えれば、缶切りが要るやつ要らないやつ何個ずつか決めれば貪欲に取るだけ。最初に要らないのを取れるだけ取って(ここも全部取れてなおM個に達しない場合や一部しか取れない場合があって注意が必要)、何個ずつ取ったか記録しておき1個ずつずらして最小値をとっていく。要るやつがKの倍数ならそこから1個増やすとコストQがかかる。解法の簡単さのわりには実装に神経を使う。まあ簡単な部類。

I - 魚釣り / PAST to Fishing

その区画までにK匹釣ったときの最大でDP。はみ出させれば境界を考える必要がないという配るDP。そこで釣ったときの遷移はその場でやって、これで最後の答えもそのまま出力するだけ。

J - ポイントとコストと / Points to Cost

Y座標の寄与は一定なのでX座標だけ考えればいいがこちらも平均を選ぶだけ(物理の計算で出てくるやつ)。癒し枠。

K - 共通クーポン / Common Coupon

捉えどころがないようにも思えるが、100で割ったあまりで分けてDPがよくわからないけど浮かぶ。商品を順番に買う買わないの選択をしてあまり100種類それぞれの最大スコアを更新していく。

REで、2次元配列の順番が逆だった。この順番は珍しいね。WAで、配列はN個じゃなくN+1個必要だねと提出するがまたWAで、あまりが0以外の場所を初期化するコードをコピペして最後の最大値を求めていたためあまりが0のときの最大値を見てなかった。まあ悪くはない3ペナ。早く楽になりたいよねー。

L - 都市計画 / Urban Planning

「交差"点"とは」って思ったけど、英語の問題文を見るとTraffic Circleだし意味はわかる(あとで調べると環状交差点って普通にある言葉なんだね)。いや無理でしょという感じ。タワーだけでも無理なので。道路が交差したところからは移動できないと書いてあるけど、環状交差点同士の場合は?交差してるならコスト0で行き来する道路を作れるから関係ないってことか。他の問題を見て戻ってくると、前もPASTであった最小全域木やんけ。点と円周の距離は中心との距離と半径の差。難しいのが円周と円周の距離で、交わるときは中心2つと交点で三角不等式が成り立つ。サンプルがかなり親切で助けられた。

M - 等しい数 / Equal Queries

平方分割が浮かぶが、実装はかなりしんどい。典型90問の23日目を思い出す。バチャ終了後とりあえず書き切ってサンプル全然通らないのも苦戦しながら細かいミスを除いていき提出。unordered_mapで定数倍がかなり重そうだがそれにしても半分以上TLEってマジかよ。WAもある(これは1個書き間違いを見つけた)。どのくらい見当外れなのかわからない。

(追記)それはさておき、寝起きで区間を思いつき、さっきそれを頑張って具体化させた。一つのクエリによってたくさんの要素が変更されても全部同じ数への変更なので、区間内は全部同じ数として数列を管理し全てのクエリを処理しても追加・削除される区間数はO(N+Q)。std::mapを使えばよい。座標圧縮はしなくてもそこまで実行時間変わらなかった。

N - 活動 / Activities

体力が0以下になったときのことが書いてないと思ったが、できるけど得点が増えないからやる意味がないってことか。活動後体力がマイナスになってもいいので難しそう。もし活動中に体力が減っていくのなら簡単になりそうなのでそれをベースに考える?いやそれもほんとかわからんか。全然わからん。

(追記)「まさかナップサックか!?」と思ったけど順番を決めることができない。こういう見た目だとDPは思いつきにくい(何か天才解法がありそうに思ってしまう)。解説を見た。あーそうやって決まるいつもの。隣と入れ替えてスコアがどう変化するかくらい見とけよー。

O - 最短距離クエリ / Shortest Distance Query

トイレで考えていたときはDFS探索木に付いた10本の辺の性質(木の親に向かう辺はないとか)が使えないかな全然わからんなという感じだった。改めて考えると、木に含まれない辺は最大11本で、その辺に含まれる頂点からそれぞれBFSすればよさそうだ。木に含まれない辺を使わないときの最短距離はLCAでわかるし、使うときは辺に含まれる頂点を経由するのでそこから見たuとvの最短距離を足せばわかる。アイデア自体は簡単だけど、LCAが入るとコードが長くなるのでBFSやこの問題特有の処理とうまくガッチャンコするところが勝負。