日本レジストリサービス(JPRS)プログラミングコンテスト2025#2(AtCoder Beginner Contest 415)に参加したので振り返り。
Cで時間をかけすぎ、わずかに下げてしまった。。。
A - Unsupported Type
\(A\) に \(X\) が含まれるか確認するだけ。
main :: IO ()
= do
main <- val ucInt
n <- list1 ucInt
as <- val ucInt
x
$ x `elem` as printYn
B - Pick Two
予め #
の位置を振っておき、前から2つずつとっていけば良い。
main :: IO ()
= do
main <- map fst . filter ((=='#') . snd) . zip [1..] <$> list1 ucChar
ss
let f [] = []
= notComeHere
f [_] :b:as) = (a,b) : f as
f (a
$ \(a,b) -> putStrLn $ show a <> "," <> show b for_ (f ss)
C - Mixture
問題の意味を理解するのに時間がかかってしまった。。。 問題文には、以下のように記載されている。
まず、 \(1\) 種類以上の薬品が混ざった状態 \(i ( 1 \le i \le 2^N −1 )\) を次のように定義する。 \(i\) を \(2\) 進法で表記した際に下から \(k ( 1 \le k \le N )\) 桁目が \(1\) である、またその時に限り、薬品 \(k\) が含まれている。
上記だけだとよくわからないので、例を挙げてみる。
\(N=3, \ S=\) 0010000
とすると、 \(S\) の \(3_{(10)} = 011_{(2)}\) 桁目が \(1\) となっている。
これは薬品 \(1_{(10)} = 001_{(2)}\) と薬品 \(2_{(10)} = 010_{(2)}\) が混ざった状態 \(011_{(2)}\) が 危険 である、という意味になる。
そのため、薬品を1種類混ぜることは、「ある \(2\) 進法で表された状態において、薬品の番号に対応する桁を \(0\) から \(1\) に変えること」に対応する。
この理解の下で、問題は次のように言い換えられる:
\(N\) 桁の \(2\) 進数において、 \(0\) である桁のいずれかを \(1\) に変更する操作を考える。 \(0_{(2)}\) から始めて、すべての桁を \(1\) とするような操作列は存在するか。 ただし、文字列 \(S\) で指定される数への変更は禁止する。
単に \(\underbrace{00\dots0}_{N}\) から \(\underbrace{11\dots1}_{N}\) に到達できるかどうかだけなので、DFSで解くことができる。
状態遷移関数 nextStatus
では、今の状態が危険なら遷移先なし、安全なら遷移先の状態を列挙する
(問題文からは、危険な状態への遷移は禁止しているように読めるが、危険な状態からは次の状態に遷移できない、としても同じである)。
main :: IO ()
= do
main <- val ucInt
t
1..t] $ \i -> do
for_ [<- val ucInt
n <- array @UArray (0::Int,2^n-1) . ((0,'0'):) . zip [1..] <$> list1 ucChar
ss
let nextStatus x = if ss ! x == '1' then []
else map (setBit x . fst) . filter ((==0) . snd) . zip [0..] <$> take n $ endig 2 x <> repeat 0
= dfs nextStatus (0,2^n-1) [0]
result
$ ss ! (2^n-1) /= '1' && result ! (2^n-1) printYn
D - Get Many Stickers
貪欲で行けそうには見えていたが、どの順番で操作するかわからず、コンテスト中には解けなかった。。。 (当初は \(A_i\) と \(B_i\) の比を考えるのかと思っていたが、それだとうまくいかない)
解説の通り、 \(A_i - B_i \equiv D_i\) が小さい順にとっていけばよく、操作の回数が本問題の答えとなる。 整数 \(i\) に対応する操作を \(x_i\) 回行う場合、現在持っている瓶入りコーラの本数を \(C\) とすると、
\[\begin{equation*} C - D_i \times x_i < A_i \Leftrightarrow x_i > \frac{C-A_i}{D_i} \Leftrightarrow x_i = \biggl\lfloor \frac{C-A_i}{D_i} \biggr\rfloor + 1 \end{equation*} \]となる。 ただし、 \(C - A_i < 0\) の場合は操作ができないため、その場合は \(x_i = 0\) とする。
main :: IO ()
= do
main <- int2
(n,m) <- L.sortOn snd . map (\(a,b) -> (a,a-b)) <$> int2list m
ablist
let f :: (Int, Int) -> (Int, Int) -> (Int, Int)
= let x = max 0 $ (bin-a)`div`d + 1
f (bin, seal) (a,d) in (bin - d * x, seal + x)
= snd $ foldl' f (n,0) ablist
result
print result
E - Hungry Takahashi
コンテスト中ちょっと触ってみたが、方針立たず。 解説を読むと、DPが想定解法とのこと。
あるマス \((i,j)\) からマス \((H,W)\) に行くために持っておくべきコインの枚数の最小値を \({dp}_{i,j}\) とする。 マス \((i,j)\) で所持金が負にならないために必要なコインの枚数は、
- マス \((H,W)\) では、「このマスで失うコインの枚数」
- それ以外のマスでは、「次のマスで持っておくべきコインの枚数」-「このマスで得られるコインの枚数」
である( \({dp}_{i,j} \ge 0\) なので、上記の値は非負)。 「次のマス」は今いるマスの右か下なので、以下の緩和式が成り立つ。
\[\begin{equation*} {dp}_{i,j} = \begin{cases} \max (0, P_{H+W-1} - A_{H,W}) & (i,j) = (H,W) \\ \max (0, \min ({dp}_{i+1,j},{dp}_{i,j+1}) - (A_{i,j} - P_{i+j-1})) & \text{otherwise} \end{cases} \end{equation*} \]main :: IO ()
= do
main <- int2
(h,w) <- intGrid h w
ag <- list1 ucInt
ps
let pa = array @UArray (1,h+w-1) $ zip [1..] ps
= runSTUArray $ do
result <- newArray ((1,1),(h,w)) (maxBound :: Int)
dp $ max 0 (pa ! (h+w-1) - ag ! (h,w))
writeArray dp (h,w)
-1..1] $ \i -> for_ [w,w-1..1] $ \j -> do
for_ [h,h/= (h,w)) $ do
when ((i,j) <- if i < h then readArray dp (i+1,j) else return maxBound
rpj <- if j < w then readArray dp (i,j+1) else return maxBound
rip $ max 0 (min rpj rip - (ag ! (i,j) - pa ! (i+j-1)))
writeArray dp (i,j)
return dp
print $ result ! (1,1)
回答見ればどういう緩和式になるのかはわかるけど、まだまだ本番でこの緩和式は思いつかない・・・
感想
C問題は、2進数の状態遷移を扱う問題があった(ABC410-D)のを思い出し、自力で実装できたのは良かった。 むしろ、問題文を読み解くのに時間がかかってしまった(薬品と状態という2つの概念の関係の理解が難しかった)。 2進数で表された情報を文字列にエンコードする、という考え方は新鮮で面白いと思ったので、覚えておこう。
D問題は、全然詰めきれなかったなという感覚。 \(A_i\) と \(B_i\) の比が同じならより \(A_i\) が小さいほうが良い、というところまでは気づけていたので、 操作で瓶入りコーラの本数がどう変化するか、計算してみたら良かったかもしれない(紙上での実験が足りなかった)
E問題、まずDPというのが思いつかなかったのと、upsolveでも降順に遷移させることに気づかず、随分時間を食ってしまった。 単純に経験が足りないだけな気もするので、どんどん問題を解いて慣れていこう。