九州大学プログラミングコンテスト2018 D - Novelist
解法
王都から都市へ移動する依頼をうけるとき、その後に王都からへ移動する依頼を受けるには、一旦から王都へ戻る依頼を受ける必要があります。
ということで、王都を出て、また王都へ戻る期間を、金貨が2枚もらえる1つの区間と見て、期間が重複しないように区間を選び、もらえる金貨の枚数を最大にすることを考えます。
すると、これは区間スケジューリングと同じことを考えることになります。
さて、あとは区間を作成していけばよいのですが、作成できる全ての区間を考慮していくと、区間の個数が大きくなりすぎてしまい、時間内に解くことができなくなってしまいます。ので、王都を出発する個の依頼について、最も効率が良くなるような、王都へ戻る依頼を個の中から探し出し、それを1つの区間とすることで、たかだか個の区間だけに絞ることができるようになります。
王都を出発してとある都市へ行く、番目の依頼について見た時、ペアとなる依頼は、
- およびを満たす依頼の中で、が最小のもの
となります。
この依頼は、個の依頼を、で分類し、それぞれの昇順でソートしておくことで、二分探索によって求めることができます。
こうしてできたペアは、という区間になります。
また、もし条件を満たすペアが存在しなかった場合、という区間を作成しておきます。これは、最終的に王都に戻る必要がないので、そのパターンに対処するためです(戻れる依頼が存在する場合は、間違いなく戻った方が得をするので、この処理を行うのは、ペアとなる依頼が存在しなかった場合のみです)。
あとは、作成した区間について、区間の後ろ側で昇順ソートをし、区間スケジューリングを行っていけば答えを求めることができます。
現在、受けると決めた依頼のうち、最後に完了する時刻をとすると、ソートした区間からについて前からみていき、現在みている区間がであったときに、
かつのときに、金貨を2枚獲得、をに更新
かつのときに、金貨を1枚獲得、をに更新
という操作を行っていけば、答えを求めることができます。
感想
区間でまとめることができる、ということに気づくと、うまく区間スケジューリングに帰着させることができます。
久々に区間スケジューリングへ帰着させる問題を解きましたが、結構すんなりと考察することができたのでよかったです!
実装も特にバグを含まなかったので安心です。