geam1113’s diary

主にAtcoderのコンテストの備忘録を書きます。AtCoder緑と水色を行ったり来たりしています。

AtCoder Beginner Contest 301 メモ

コンテストページ: パナソニックグループプログラミングコンテスト2023(AtCoder Beginner Contest 301) - AtCoder
コンテスト中AC: A〜C
コンテスト後にD,Eを自力AC

D - Bitmask

以下の説明で、Nの最大値を十分に超えるため、最上位ビットを63としておきます。Sがこれより小さい場合はサイズが63になるように0を追加しておきます。

上位のビットから?のビットを決定していくことを考えます。上位ビットをできるだけ大きくした方が、値として大きくできるため、優先します。

この時、Nより小さい数にするために、?を使うのは高々1箇所であると言えます。なぜなら、一度N未満となれば、その後の下位ビットをどのようにしたとしても、N以上となることはありえないからです。

仮にi番目のビットでSN未満であることが確定した場合に最適解であったとします。この時、最上位ビットからi+1番目までのビットはNSで一致していることが言えます。

もし一致していなければ、i番目より上位のビットでSN未満であるか、Nより大きいかのいずれかとなってしまいます。

また、i-1番目以降の?は全て1にするのが最適です。

SN未満にするというのは、Niビット目が1であり、かつ、Siビット目が?である状況で、?を0にすることと言えます。

そこで、Sの?を1つずつ0にした場合について、その時のSの最大値を全探索します。この時、

L_i:=Sの最上位ビットからiビット目までについて、?の箇所を全てNと同一にし、i-1以降は0であるような値

R_i:=Sの0ビット目からiビット目までについて、?の箇所を全て1とし、i+1ビット目以降は0であるような値

となるように配列L,Rを作っておくと、iビット目でN未満となった時の値をL_{i+1}+R_{i-1}で計算できます。但し、便宜上、L_{64}=R_{-1}=0とします。(ビットを1オリジンで実装すれば-1が0になって実装しやすくなります。)
解の最大値の更新は、この値がN以下である場合のみ行えばよいです。

テーブルはO(N)で構築でき、全探索もO(N)でできます。

なお、N未満となる箇所が0箇所の場合も考慮する必要があります。これは、R_{63}と同じです。

実装: Submission #41405709 - Panasonic Programming Contest 2023(AtCoder Beginner Contest 301)

E - Pac-Takahashi

同じお菓子を2回食べられないので、既に食べたお菓子の状態を冪集合で管理したいです。状態数分のマスを拡張したBFSはおそらく計算量的に厳しいです。

考慮すべきは、スタート-お菓子、お菓子-お菓子、お菓子-ゴール間の最短距離のみです。また、後は各状態に対する移動距離の最小値が求められればよいです。ここで思いつくのが巡回セールスマン問題です。

お菓子を頂点とみなします。また、計算量は定数倍落ちますが、実装の簡便さからスタートとゴールも頂点とみなします。
これら頂点に対する巡回セールスマン問題を考えると、状態Sで頂点uにいる場合の最短距離を、頂点数をNとしてO(N^2 2^N)で求めることができます。

最短距離を求めた後は、ゴールの頂点にいるdp値について、T以下か調べます。T以下であれば、冪集合の1の数をカウントし、更にそこからスタートとゴールの頂点数2を引いた値で、答えの最大値を更新すればよいです。

全点対間最短経路は各頂点からBFSすることで、O(HW)で求められます。

実装: Submission #41471658 - Panasonic Programming Contest 2023(AtCoder Beginner Contest 301)

なお、詳細は割愛しますが、スタートとゴールは巡回セールスマン問題を解く時の頂点から除いて考えることができ、定数倍軽くなります。但し、例外処理などに気をつける必要があります。

実装: Submission #41471658 - Panasonic Programming Contest 2023(AtCoder Beginner Contest 301)