競技プログラミングのためのF#入門
考え方としてはユーザー解説の方がわかりやすいでしょう. 引用します.
で、これらを考えていくと、回転させるのは、ある同一方向を向いている塊を回転させれば良さそうということになる。 やっと400点レベルにまで落ちてきた。 方向が一致している区間を縮約するとLRLRLRやRLRLRLになっているはず。 例えばLRLRLRの最初のRを回転させるとLLLRLRでLRLRとなり、方向が一致していない箇所が2つ減る。 なので、LかRのどちらかを貪欲に回転させて、方向不一致の区間を減らしていったときの幸福人数が答え。 幸福人数はN-(LかRのグループ数)となる。各グループで1つは幸福でないため。
あとはこれをどうコードに落とし込むかにかかっています.
最大値を計算する部分に集中します.
2
だけ幸福度が上がる. 特に最大2*K
だけ幸福度が上がる.この和を取れば幸福度最大の状況の幸福度が計算できるはずです. ただしLLLLLRRRRR
の例のような真の最大幸福度が実現される場合, 問題の制約によって端の人の幸福度の処理が必要で, この処理を忘れてはいけません.
F#の文字列は文字列のモジュールもある一方で文字のシーケンス(Seq
)です. 文字列のモジュールにほしい処理がなくても, シーケンスの関数を拝借して処理できます. 実際Seq.pairwise
で前後ペアのシーケンスが取れるため, これで元の幸福度計算用の処理を進めればいいでしょう. 例えば次のような結果が得られます.
1 2 3 4 |
|
前後ペアを取った結果のシーケンスから幸福度を計算するには, シーケンスのたたみ込みで和を取ればよく, 典型的にはSeq.fold
で計算できます. ここではSeq.sumBy
を紹介します.
1 |
|
これが処理の本体で, あとは次の通りです.
1 2 3 4 5 6 7 |
|
HaskellにはあってもF#にはない便利関数は数限りなくある一方, 珍しくHaskellだと前後ペアを作る便利関数がないようです. こういう場合はzip
やzipWith
を使うのが典型的な処理です. そしてHaskellコードの移植時に慣れていないとはまる部分でもあります. ちなみにHaskellのzipWith
はF#だとSeq.map2
です.
さてどうやって前後ペアを作るかというと, zip
を使って二つのシーケンスをタプルのシーケンスにまとめます.
1 2 3 4 |
|
上の例のようにシーケンスのzip
は二つのリストの長さが一致しなくても短い方に自動的に合わせてくれます. しかしリストや配列では長さが違うとエラーになるため注意してください.
これを使うと前後ペアは次のように作れます.
1 2 3 4 5 |
|
あとは実装1と同じように処理すれば求める結果が得られます.
Previous: 074 D - Harlequin Next: 076 C - たくさんの数式 back to top