完成した数列はどこかで符号がマイナスからプラスに切り替わることに注目する。N=5なら、
- +++++
- −++++
- −−+++
- −−−++
- −−−−+
- −−−−−
の6通りがありえる。たとえばA3で符号が切り替わると決めてしまうと、あとはA3,A4,A5の好きな数に好きなだけ4を掛けて単調非減少にして、A2,A1にも4を掛けて単調非減少にして、最後にA2,A1に−2を掛ければ全体として単調非減少になっている。
そこで、f+(x):=Ax,Ax+1,...,ANを単調非減少にするための最小コスト、と定める。おそらくf+(N+1)=f+(N)=0からスタートしてx=N−1,N−2,..と順にf+(x)の値を求めていけそう。さらに、f−(x):=Ax,Ax−1,...,A1を単調非減少ににするための最小コスト、とすれば(f−(x)+x)+f+(x+1)の最小値が答えになる。(+xは−2を掛けるぶんのコスト。)
さて、f+を求める具体的な方法が問題になる。この手順が与えられれば、f−は同じ方法を逆順の配列に適用するだけでよい。先に述べた通り、f+(N+1)=0からスタートして降りていくことにする。とりあえず、正しくないがシンプルな方針から:
- Ax≤Ax+1ならf(x):=f(x+1)。
- Ax>Ax+1ならAx+1に何回か4を掛けて非減少になるようにする。つまり、Ax≤4kAx+1となるような最小のkを求めて、以降のAx+2,...,ANにも同じだけ4を掛ける。このとき、f(x):=f(x+1)+2k(N−x)となる。
この方法の問題点は入力例1に適用してみればわかる:
4
3 1 4 1
f(5)=0,f(4)=0,f(3)=2,f(2)=2までは正しく求まるが、A1=3を処理する際に4を掛ける必要があるのはA2=1だけで、A3,A4はそのままでいいことを見落としていた。つまり、A2,A3の間にはすでに4倍の差があるので、一回分の4掛けに限ってはA2で吸収されてしまうことになる。一般に、Ax+1がAxの4k倍以上である時、k回ぶんの4掛けはAxに吸収されてAx+1以降には影響しない。このkをxの 容量 と呼ぶことにする。上の手順で降りていくとき、各Axについて(容量が正なら)(x,容量)のペアをスタックに積んでいくことにする。
- Ax≤Ax+1ならf(x):=f(x+1)。xの容量が正ならスタックに(x,容量)を積む。
- Ax>Ax+1ならAx+1に何回か4を掛けて非減少になるようにする。つまり、Ax≤4kAx+1となるような最小のkを求める。スタックの先頭が(y,容量)になっているとき、Ax+1,...,Ayにmin(容量,k)だけ4を掛ける。このとき、操作回数は2min(k,容量)(y−x)だけ増えるが、容量がkより小さい場合はさらにスタックをポップしながらk回の4掛けが終わるまで繰り返す。
各インデックスについて、スタックへのpushとpopは1回しか行われないので、スタック操作は全体でO(N)になっている。