はじめに
テンプレは別記事.
A
問題文 : https://atcoder.jp/contests/abc423/tasks/abc423_a
引き出せる回数は $\left\lfloor \frac x { 1000 + c } \right\rfloor$ で,これに $1000$ を書けたものが答えです.とりあえず普通に計算します.
main = do [ x, c ] <- readInts print $ x `div` ( 1000 + c ) * 1000
これはこれでいいんですが,ワンライナーパズルもやります.[Int] を読む関数は皆さん用意していると思うので*1,readInts >>= の右側の話をします.
まず,リストのままだと扱いづらいので,いつものように Control.Arrow の (&&&) を ( head &&& last ) のようにしてタプルにします.次に第 $2$ 要素に $1000$ を足しますが,これまた Control.Arrow(または Data.Tuple.Extra)にある second を使うと第 $2$ 要素にだけ関数を適用した新たなタプルを作れます.これで div の引数が作れたので,uncurry div に渡せば引き出し回数が求められて,あとは $1000$ 倍するだけです.
main = readInts >>= print . ( * 1000 ) . uncurry div . second ( + 1000 ) . ( head &&& last )
B
問題文 : https://atcoder.jp/contests/abc423/tasks/abc423_b
まず,全て $0$ の場合は $0$ です.そうでない場合,先頭・末尾からそれぞれ連続する $0$ を取り除いた後で,$\text{残ったリストの長さ} - 1$ が答えです.
リストの先頭・末尾から条件を満たす限り要素を取り除くのはそれぞれ dropWhile, dropWhileEnd です.$1$ を引く関数 pred があるので $\text{長さ} - 1$ は pred . length でできて,全部 $0$ のときにこの値が $-1$ になるのを max 0 でケアします.
値を順に加工していくだけなので最初からワンライナー風で.
main = getLine >> readInts >>= print . max 0 . pred . length . dropWhileEnd ( == 0 ) . dropWhile ( == 0 )
C
問題文 : https://atcoder.jp/contests/abc423/tasks/abc423_c
詳細は割愛しますが,$r$ 番目の要素を含まない範囲で先頭・末尾からそれぞれ連続する $1$ を取り除いた後で,$\text{$0$ の個数} + 2 (\text{$1$ の個数})$ が答えです.
添字と要素を同時に見たいので [ 1 .. ] と zip してから,B 問題と同じように dropWhile, dropWhileEnd で切り落とします.
count a as = length $ filter ( == a ) as main = do [ n, r ] <- readInts ls <- readInts let ls' = map snd $ dropWhile ( \( i, a ) -> i <= r && a == 1 ) $ dropWhileEnd ( \( i, a ) -> r < i && a == 1 ) $ zip [ 1 .. ] ls print $ count 0 ls' + 2 * count 1 ls'
D
問題文 : https://atcoder.jp/contests/abc423/tasks/abc423_d
店内のヒトビトについて,団体の人数と退店時刻を管理します.列の先頭の団体を受け入れる度に,退店時刻が早い順に退店させる処理をしたいので,店内のヒトビトは退店時刻の昇順に取り出せるようなデータ構造に入れたいです.今回は,Data.Set を使います.ただし Data.Set は多重集合ではないので,簡易的な対応として「何番目の団体か」を表す整数を Data.Set の要素に付け加えて擬似的に多重集合にします.
処理の大まかな構造としては「店内の状態を表す何か」に来店団体の列を畳み込むような形になるので,mapAccumL で畳み込みます.状態としては店内の情報に加えて最後に何か(入店 or 退店)が起こった時刻ももっておく必要があるので,時刻・店内の人数・退店予定の $3$ 要素タプルになります.
畳み込む関数の中身については,技術的な話題がどういつよりシミュレーションに使う値をそれぞれ計算するだけなので割愛します.
main = do [ n, k ] <- readInts [ as, bs, cs ] <- transpose <$> replicateM n readInts mapM_ print $ snd $ mapAccumL ( solve k ) ( 0, 0, Set.empty ) $ zip4 as bs cs [ 1 .. ] solve k ( t, v, s ) ( a, b, c, q ) = let ( t', v', s' ) = first3 ( max a ) $ pop t v s in ( ( t', v' + c, Set.insert ( t' + b, c, q ) s' ), t' ) where pop t v' s' | k < v' + c = let ( ( t', c', _ ), s'' ) = Set.deleteFindMin s' in pop t' ( v' - c' ) s'' | otherwise = ( t, v', s' )
E
問題文 : https://atcoder.jp/contests/abc423/tasks/abc423_e
詳細は別記事を参照願いたいですが,立式していじくり回す部分が一番むずかしい気がします.
実装面では列 $\langle 1^kA_1, 2^kA_2, \dots, n^kA_n \rangle$ ($k \in \{ 0, 1, 2 \}$) という列を作る部分には工夫する余地があって面白いです.内包表記を $3$ つ書いてしまってもよいのですが,やや冗長というか面倒くさい感じがするのでもう少し考えます.列 $\langle 1, 2, \dots, n \rangle$ に何かを map して $3$ つの列 $\langle 1, 1, \dots, 1 \rangle, \langle 1, 2, \dots, n \rangle, \langle 1, 4, 9, \dots, n^2 \rangle$ を作る方法を考えます.とはいえトリッキーなのはひとつめだけで,$1$ を返す定数関数を渡せばよく,コードでは const 1 です.残りふたつは id と (^2) です.
これら $3$ つの関数をそれぞれ map する処理をスッキリ書きたいですが,関数のリストに map を map すると「リストを受け取って map 後のリストを返す関数」のリストが得られます.あとはこれを [ 1 .. ] にそれぞれ適用したいですが,Applicative という概念を思い出すと関数のリストを作る部分もまとめて map <$> [ const 1, id, (^2) ] <*> [ [ 1 .. ] ] になります.あとはそれぞれ $i$ 番目の要素を $A_i$ 倍すれば目的の列なので,zipWith (*) as すればできあがりです.
あとは累積和を取ってから配列にすればよいので,scanl で累積和にして,アクセスの高速化のために listArray で配列にしておきます.
仕上げにクエリを読みながら値を計算して答えのリストを作り,mapM_ print で出力すれば終わりです.
main = do [ n, q ] <- readInts as <- readInts queries <- replicateM q readInts let psums = listArray ( ( 0, 0 ), ( 2, n ) ) $ concat $ map ( scanl (+) 0 . zipWith (*) as ) $ map <$> [ const 1, id, (^2) ] <*> [ [ 1 .. ] ] rsum i l r = psums ! ( i, r ) - psums ! ( i, l - 1 ) mapM_ print do [ l, r ] <- queries return $ -rsum 2 l r + ( l + r ) * rsum 1 l r + ( r - l - l * r + 1 ) * rsum 0 l r
*1:ByteString で読まないと遅くて,毎回書くのは面倒ですのでね.