AtCoder Beginner Contest #125
A. Biscuit Generator
切り捨てをする. 解答例
回生産できるとするとはを満たす最大の整数.と変形すると切り捨てだと分かりやすい気がする.
B. Resale
制約が小さいので全探索してしまった.は程度なので間に合う. 解答例
実際は価値>コストでさえあれば手に入れてしまって損しないから,そのようにすればよい.AtCoderのOCamlは古いのでmap2
が使えず1CE. 解答例
C. GCD on Blackboard
過去問演習 (No Need) の経験が生きた:理解できなくて記事に書けなかった累積和版の解答をおぼろげに覚えていたおかげで速答できた(添字の凡ミスで1WA). 解答例
制約からくらいで解きたいので,とりあえず配列の中身を順番に見る方向で考える.ひとまず番目を書き換えるか否かですべて試す方針を思いついた.しかしこの場合,番目以外の全整数のgcdが得られなければならない. 毎回愚直に計算すると掛かり間に合わないため工夫が必要.
これは最初に右方向と左方向にそれぞれ累積gcdを取っておけばよい(それぞれ配列とする).すると番目より左の整数のgcdは,右はで得られる.これは構築に,取得にしか掛からないから,全についての試行に掛かる時間計算量はとなり間に合う.
gcdの計算量は小さいほうの桁数,すなわち.
別解: Segment Tree
1位の方がSegment Treeを使っていたので真似してみた.確かにintに対するには単位元が存在するし,結合則が成立するからモノイドである.今回は更新はしないが,それでもに対する演算結果を取れるので便利. 解答例
現在のSegment Treeの実装はOCamlとして汚い上にかなり遅いのでこれも何とかしたい.
D. Flipping Signs
このような隣り合う2つをひっくり返すような問題は何度か見たことがあったので経験が生きた. 解答例
editorialにあるように添字について操作を行えばの符号だけを反転可能であるから,これを繰り返すことで「添字を2つ選んでそこの符号を反転させる操作ができる」と見做せる.したがって負数が偶数個であればすべてを正にできる.奇数個であれば1つの整数は負のままとなるが,負にする整数は絶対値が最小なものを選ぶのが最適なのでそのようにする(負にするにはペア(現在負の整数, 負にしたい整数)に対して先の操作を行えばよい).
別解: 動的計画法 (editorial)
番目を負にするか正にするか選ぶときに番目以前の状態自体には関心が無い(和だけあればよい)から,和が最大な状態だけを選ぶことで状態を纏めることができる. 解答例
まず前に操作をしたときとそれ以外とでそれぞれ別のdp配列を用意することが必要(名前はpositiveとnegativeの意味).このときはあり得ないことに注意[1].
遷移を考える.まず操作をしないとき,すなわちについて考える.前に操作をしていなかった場合はそのままを加算することになるから,.前に操作をしていた場合は「操作をした場合のdp配列」であるからを引くことになる:.これらの最大値を採用すればよい.
つぎに操作をする場合,すなわちの更新について考える.前に操作をしていなかった場合はは反転していないから,反転は計1回であり.前にも操作をしていた場合はは一度反転しているから再度反転させることになり,翻って元のままのとなる:.
値を極端に小さくしてそのような場合が採用されないようにすればよい.
min_int
(AtCoderなどの64bit環境では)とすると何か引かれたときに負方向にオーバーフローして極端に大きくなってしまうため,などを採用するべき.和の最大および最小値はでしかないからここから出た結果がを超えることも負方向にオーバーフローすることもない. ↩︎