A10 - Resort Hotel¶
- created: 2022-12-28 wed
- ご意見・ご要望はissue・プルリク用のGitHubまで
- 競技プログラミングのためのF#入門
- GitHub上の対応ディレクトリ
- 公式ページ
- 要点: アルゴリズム, ループを減らす
入出力¶
1 2 3 4 5 | |
方針¶
ふつうに都度計算していたら凄まじい時間がかかるため, やはりクエリ処理の前の事前計算が重要です. 真ん中を抜いた配列に対する最大値の計算は, 左からLi-1番目までの最大値と, 右からRi+1番目からの最大値を計算すればよいです. 特に左からi番目までの最大値と, 右からi番目までの最大値を比較すればよいため, これを事前に計算しておけば十分です.
この方針さえ立てばあとは素直に実装できます.
解説¶
命令型的にforを回す計算でも対応できます. ここでは関数プログラミングらしい処理としてscan maxを使います.
1 2 | |
Laが左からの最大値でRaが右からの最大値です. それぞれ左右の端からはじめるにはscanとscanBackと使えばよいです. 気分としてscanBackはArray.rev >> Array.scanだと思ってください. 上のコードを見ればわかるように初期値0とAaの引数の順番が入れ替わっています. ちなみにscanとscanBackはHaskellだとfoldlとfoldrで, このlとrはleftとrightに由来します.
あとはクエリごとに最大値を比較すれば終わりです.
1 | |
scanとscanBackは初期値0に由来する「余計な項」が入っている点に注意して添字を指定してください. 公式の入力例でLaとRaは次のようになっています.
1 2 | |
scanでは最初に0が, scanBackでは最後に0が入ります. REPLを使うと簡単に確認できます.