競技プログラミングのためのF#入門
GitHub上の対応ディレクトリ 公式ページ 要点: アルゴリズムの検討 入出力
| let N = stdin.ReadLine() |> int
let Aa = stdin.ReadLine().Split() |> Array.map int64
solve N Aa |> stdout.WriteLine
|
解説
公式解説通りに実装します.
MOD計算
計算漏れしないように演算子を定義してそれを使いましょう.
| let MOD = 1_000_000_007L
let (.*) a b = (a*b)%MOD
|
MOD
はInt32
でも問題ないと思いますが, たまにオーバーフローしてはまり倒すため, 怪しそうな場合はとにかくInt64
に倒します.
大枠
各i
ごとに計算した結果をかけて積んでいけばよく, 単純にArray.fold
でループを回します. 変数名は公式解説に合わせます.
積む変数は最終的な計算用の値であるTi
とxi,yi,zi
です. 前の人までの帽子の値が必要なためxi,yi,zi
もState
に積む必要があります. 初期値はかけ算の初期値だからTi = 1
, 帽子の数は(xi,yi,zi) = (0,0,0)
でよく, 特に次のように書けます.
| ((1L,(0L,0L,0L)), Aa)
||> Array.fold (fun ((t,(x,y,z)) ai) -> ("適切に埋める")
|> fst
|
最終的に必要なのはt
の値だからそれをfst
で切り取ります. タプルを切り取るのはfst
とsnd
までしかないため, この最後の切り取りが単純になるようにState
を構成しています.
folder
の構成
まずt
を更新します. filter
とlength
を組み合わせるのが素直な実装です. ここではsumBy
で次のように処理します.
| let ti = [|x;y;z|] |> Array.sumBy (fun w -> if w=ai then 1L else 0L)
|
いまはInt64
でt
を積むため, filter >> length
で処理する場合は最後にint64
をかませる必要があります.
次は(x,y,z)
の更新です. これは単純な場合分けで十分です.
| let xyz = if ai=x then (x+1L,y,z) elif ai=y then (x,y+1L,z) else (x,y,z+1L)
|
あとはこれらの値をタプルにまとめて次のステップに回します.
MOD
つきのかけ算にするよう注意しましょう.
まとめ
ここまでの処理をまとめると次のように書けます.
1
2
3
4
5
6
7
8
9
10
11
12
13 | let solve N Aa =
let MOD = 1_000_000_007L
let (.*) a b = (a*b)%MOD
((1L,(0L,0L,0L)), Aa)
||> Array.fold (fun (t,(x,y,z)) ai ->
let ti = [|x;y;z|] |> Array.sumBy (fun w -> if w=ai then 1L else 0L)
let xyz = if ai=x then (x+1L,y,z) elif ai=y then (x,y+1L,z) else (x,y,z+1L)
(t.*ti, xyz))
|> fst
let N = stdin.ReadLine() |> int
let Aa = stdin.ReadLine().Split() |> Array.map int64
solve N Aa |> stdout.WriteLine
|
Previous: 088 D - XOR World Next: 090 D - Even Relation back to top