九州大学プログラミングコンテスト2018 E - Treeone
解法
まず、を変える、としたとき、どんな数字に変えればよいか、ということを考えてみます。
このとき、部分列の総和に影響がでるのは、もちろんを部分列に含むものについてのみで、含まないものは総和が変化することはありません。
さて、もともとを部分列に含み、かつ総和が0であったものについては、必ず総和が0ではなくなるので、その分たぴさが減少します。
逆に、総和が0でなかった場合、の数字の変更によって、総和が0になってしまうパターンが存在します。
現在の総和がで合った場合、を、にしてしまうと、その部分列は総和が0になり、たぴさが上昇します。逆に、この値以外であれば、たぴさが上昇することはありません。
全ての部分列について、このような”変更後に総和が0になってしまう値”が存在しますが、逆にそれらとは違う、別の値に変更することによって、確実にたぴさの上昇を抑えることができます。
結果として、を変更する、と決めたときのたぴさの最小値は、
- を含まない部分列のうち、総和が0になるものの個数
となります。あとはこれを計算することができれば、答えを求めることができます。
を含まないものについて考えるので、まず区間をに分割することができます。
で総和が0になる部分列の個数を求めることについて考えます。
とします。
になるには、となる必要があります。
つまり、部分列の右端がになるような、部分列の総和が0になる区間の個数は、となるようなの個数、となります。
ということで、となるようなの個数を、をキーとするmapか何かに格納しておくことで、累積和を計算しつつ、mapの更新を行い、区間の右端がとなるような、総和が0となる部分列の個数を求めることができます。
で総和が0になる部分列の個数は、部分列の右端がになるような、部分列の総和が0になる区間の個数の累積和をまでとることで求めることができます。
そして、については、数列をさかさまにして、同様の操作を行うことで求めることができます。ので、あとは、変更する数字の場所を全探索して、それぞれにおけるたぴさの最小値を計算していけば、その中で最も値が小さかったものが答えになります。
感想
両側から見る、という発想ができませんでした。自分が作成した問題で同じものがありましたね…