ABC336 参加の感想

目次に戻る

概要

ABC336のリンクですよ!
結果 : ABCDE.. 5 完(27:21 + 5:00)(1WA).
パフォ : 1949
レート : 19461946(+0)
いやー、終了後に Twitter を見たら F が半分全列挙って書いてあって、 あーーーーーってなった。スタートとゴールが決まっている系はできるんだなぁ・・・ ずっとヒューリスティックに解くことばっかり考えてたせいで、こういう単純な解法を見逃すんだよなぁ。 まあ、 F で書くか。

A - Long Loong

まあ、言われたとおりにやった。

B - CTZ

__builtin_ctz() が便利。

C - Even Digits

$N-1$ を $5$ 進数にして、すべての桁に $2$ をかけたものが答えになる。

$0$ が出力できていなくて 1WA を出した。

D - Pyramid

連続部分列について見る問題。 左から $1$ からの $1$ ずつ増加する増加列を作ってみて、途中で作れなくなったときは、 その $i$ を $A_i$ 番目にした増加列として考えられるので、これを左から求めるのと、 同じように右から求めたものについて min をとってあげるとその位置を真ん中としたピラミッド数列の 最大の大きさがわかる。

E - Digit Sum Divisible

なにか作ってみて、割り切れるかどうか系は大体 DP 配列にあまりを入れる系が多い気がする。 特に、今回は桁和のバリエーションが $126$ 個しか無いのでかなり考えやすい。 まず桁和の値を決め打ちする。仮に $d$ と置いておく。 すると、このような DP が可能になる。今回は桁 DP である。

$\mathrm{dp}[i][j][m][k]$ ... 大きい桁から $i$ 番目を見ていて、 現在 $N$ と同じ値をずっと使ってきた場合は $k=0$, そうでない場合を $k=1$ とする。 このとき、これまでの桁和が $j$ であり、それまでの値を $d$ で割ったあまりを $m$ としたときの 整数の個数
これを考えると、最終的に桁数を $S$ とか置くと、 $\mathrm{dp}[S][d][0][0] + \mathrm{dp}[S][d][0][1]$ に答えがでてくることになる。 計算量は $B$ 進数だとして( 今回は $B=10$ )、 $O((B \log_{B} N)^{4})$ になっているのかな。

F - Rotation Puzzle

なんでこれが思いつかないんだーという感じ。 まず $k$ 回操作を行うときの計算量は、同じ操作を行わないことを利用すると、パターン数が $4 \times 3^{k-1}$ になる。 これに $HW$ がかかってくる感じになる。 自分はヒューリスティックに枝刈りしようと思ってずっとやっていたが、実は半分全列挙ができる。

スタート地点から $10$ 回までの操作をすべて保存しておく。 そしてゴール地点から $10$ 回のまでの操作をすべて保存しておく。 そしてその中から、同じ状態のものを見つけてそれの操作回数を求めて min していくだけだった。

それぞれの状態の数は最大で $4 \times 3^9 = 78732$ であり、データの数で言えば $HW$ がかかってくるので、 $5038848$ 個くらいになる。これを map でそこまでたどり着くための最小コストを持ち、 片方を一つずつ調べていけば解くことができる。

かなり危うそうに見えるが通すことができる。

アルゴの問題なので、ヒューリスティクスな解法はあんまりないよなぁと思えばよかったが、 そっち側で考えて実装し始めたら何も考えなくなってしまうくせがある。 スタートとゴールが与えられたら半分全列挙について考えるのは手癖にしていきたい。 ちなみに A* を実装していた。md が弱いので通らない。

分かりづらい図を用意しました。探索範囲が小さくなってるよみたいな図式。

赤側から距離 10 を超えるもののうち、青側に入ってないものは明らかに見る必要がないため探索範囲が絞られる。

感想

ABCDE はいい感じだと思う。E は少しテンパって変なコードを書いたがすぐに取り直せたので問題はなかった。 結果として早解きでパフォーマンスが維持できた。

F, いやーこれが思いつかないかという感じだった。ずっと言ってるけどでも本当にそうだと思う。 でも確かに、パズル系の問題を全探索で解くという場合に逆側から考えるという発想をしたことがなかったので、 まあ妥当なのかなと思った。

(2024/01/14 23:32)

追記

F についてだが、こういう問題だけじゃなくて何か中継地点を見つけながらやっていく系も半分全列挙が使えそう。 パターンを二次元みたいに考えると、円の重なるところだけを見るような感じで考えるのが良いのかな。

まあ半分全列挙と言うよりかは、双方向探索っていうちゃんとしたワードがあるから知ってればできたんだよなぁ。 Wikipedia を見てみたら、A* との比較で使われているようだから、A* を思いついたらそっちも思いつけると吉かもしれない。

あと、E を半分全列挙でといてみたが、これかなり辛い。列挙する桁和と、最終的な桁和が違うので、それぞれに対応するために計算量が ちょっと多くなる。ただ半分全列挙でよくあるソートはないみたい。これも半分全列挙と呼んで良いのか。

(2024/01/15 02:02)
目次に戻る