AGC005 B - Minimum Sum
解法
番目の数字、が採用される区間について調べてみます。
となる区間について、がその区間の最小値になるには、かつとなる任意のについて、が成り立たなければなりません。
こうなるようなの候補の最小値、の最大値を求めてみます。
これが計算できれば、が最小値となる区間の個数を利用して、
という計算をすべてのについて行い、その和を取れば答えとなります。
は、となるようなの最大値、はとなるようなの最小値です。
このままでは、一見簡単に求めるのが難しいように見えます。しかし、上のような条件を満たすが存在しない場合、すなわちが区間全体における最小値だった場合は、問答無用では区間の左端、は区間の右端になります。このことを利用します。
例えば、下のようなの数列について考えてみます。
最初、区間全体を見ます。
の区間にあるの最小値はもちろんになります。
ということで、として、 を計算すると、
となります。
が絡む区間はすべて見終わったので、これを含まないような区間を調べます。すると、区間がちょうど2つに分かれます。
とです。
この新しくできた2つの区間について、それぞれの区間の中での最小値と、その位置を調べます。
前者は、で、後者はです。
同じように を計算してあげると、それぞれ
となります。
これで、およびが絡む区間を見終わったので、また区間を分けていきます。もし、最小値が端にある(今回ののような)パターンについては、新しい区間は1つしかうまれません。
この操作を、最終的に区間の幅が1になるまで繰り返していきます。
こうして、 を計算していって全ての総和を取れば、答えがでてきます。
区間の最小値を取り出すのは、RMQを利用します。配列のインデックスは、ペアか何かで持たせておけば大丈夫です。
操作をまとめると、はじめはとして、
について、その区間内の最小値とそのインデックスを探します。そして、
を計算します。その後、
との新しい区間について、同じことを繰り返していきます。
そして、計算した の総和を取れば答えになります。
調べたい区間をペアで管理し、新しく調べたい区間が出てくるたびにキューかスタックに格納していき、1つの区間を調べ終わったらまたそこから区間を1つ取り出していく、というようにすると、いい感じに調べることができると思います。
感想
てこずりました。ある数字が加算される(区間の最小値になる)条件と個数を調べていくのだろうな、とは思ったのですが、それを調べる方法がなかなか思いつきませんでした。
思考の過程としては、まずが最小値になるときのことを考えると、その区間は、一定の場所までは区間を広げても常に成り立ち、一回条件を満たさなくなるとそれ以降区間をどれだけ広げても再び最小値になることはないことを確認します。すると、その区間が一番広い場所を探すことができれば、が最小値になる回数がわかるので、を計算するだけでよいことになります。あとは、一番広くなる区間を探すだけなのですが、最初はを昇順に見ていってうまく処理できないかということを考えていました。結局それで調べる方法が思いつかなかったので悩んでいると、逆に、ある区間に対しての最小値を求めれば、その区間が答えになる、ということに気づいたので、上のような解法を思いつきました。