Official

D - 道路の整備 / Road Maintenance Editorial by admin Editorial for printing

gpt-5.5-high

概要

各区画の高さは増やすことしかできません。
そのため、条件 \(|A_i' - A_{i+1}'| \leq D\) を満たすために、各区画を最低限どこまで高くする必要があるかを求め、その分だけコストを払えばよいです。

考察

最終的な高さを \(H_i\) とします。

条件より、隣接する区画の高さ差は最大 \(D\) なので、任意の区画 \(j\) の高さ \(H_j\) が分かっているとき、区画 \(i\) の高さは少なくとも

\[ H_j - D|i-j| \]

以上でなければなりません。

また、操作では高さを下げられないので、

\[ H_j \geq A_j \]

です。

したがって、任意の区画 \(i\) について、すべての区画 \(j\) から次の制約を受けます。

\[ H_i \geq A_j - D|i-j| \]

よって、区画 \(i\) の最終的な高さとして必要な最小値は

\[ H_i = \max_{1 \leq j \leq N} \left( A_j - D|i-j| \right) \]

です。

この \(H_i\) は、すべての区画からの制約を満たす最小の高さです。
コスト \(C_i\) はすべて正なので、必要以上に高さを上げても得をすることはありません。

したがって、各区画を

\[ H_i - A_i \]

だけ上げるのが最適です。


ただし、各 \(i\) についてすべての \(j\) を調べると \(O(N^2)\) になり、\(N \leq 10^6\) では間に合いません。

そこで、左から来る制約と右から来る制約に分けて考えます。

区画 \(i\) に対して、左側 \(j \leq i\) から来る制約は

\[ \max_{j \leq i} \left( A_j - D(i-j) \right) \]

です。

これは左から順に見ていくことで求められます。

同様に、右側 \(j \geq i\) から来る制約は

\[ \max_{j \geq i} \left( A_j - D(j-i) \right) \]

で、これは右から順に見ていくことで求められます。

最終的に必要な高さは、この 2 つの最大値です。

アルゴリズム

まず、左から順に見て、各区画に対して左側から要求される最低高さを求めます。

左側からの必要高さを \(L_i\) とすると、

\[ L_i = \max(A_i, L_{i-1} - D) \]

です。

なぜなら、区画 \(i-1\) で必要だった高さは、区画 \(i\) では最大で \(D\) だけ低くてもよいので、\(L_{i-1} - D\) になります。
ただし、区画 \(i\) 自身の元の高さ \(A_i\) より低くすることはできないので、最大を取ります。

次に、右から順に見て、右側から要求される最低高さを求めます。

右側からの必要高さを \(R_i\) とすると、

\[ R_i = \max(A_i, R_{i+1} - D) \]

です。

区画 \(i\) の最終的に必要な高さは

\[ H_i = \max(L_i, R_i) \]

です。

したがって、区画 \(i\) で増やす量は

\[ H_i - A_i \]

であり、コストは

\[ (H_i - A_i) \times C_i \]

です。

これをすべての区画について合計すれば答えになります。

計算量

  • 時間計算量: \(O(N)\)
  • 空間計算量: \(O(N)\)

実装のポイント

左からの必要高さを配列 req に保存します。

cur = -10**18

for i, a in enumerate(A):
    cur -= D
    if a > cur:
        cur = a
    req[i] = cur

これは

\[ L_i = \max(A_i, L_{i-1} - D) \]

を計算しています。

次に右から見て、右側からの必要高さを計算しながら、左側の値と最大を取ります。

cur = -10**18

for i in range(N - 1, -1, -1):
    cur -= D
    if A[i] > cur:
        cur = A[i]

    req[i] = max(req[i], cur) - A[i]

この時点で req[i] は、区画 \(i\) を何だけ高くする必要があるかを表します。

最後に、入力されたコスト \(C_i\) と掛け合わせて合計します。

ans = 0
for x, c in zip(req, map(int, input().split())):
    ans += x * c

答えは最大で非常に大きくなる可能性があるため、他の言語では 64 bit 整数型を使う必要があります。Python では整数の桁あふれを気にする必要はありません。

ソースコード

import sys

def main():
    input = sys.stdin.buffer.readline

    N, D = map(int, input().split())
    A = list(map(int, input().split()))

    req = [0] * N
    cur = -10**18
    d = D

    for i, a in enumerate(A):
        cur -= d
        if a > cur:
            cur = a
        req[i] = cur

    cur = -10**18
    for i in range(N - 1, -1, -1):
        a = A[i]
        cur -= d
        if a > cur:
            cur = a
        v = req[i]
        if cur > v:
            v = cur
        req[i] = v - a

    ans = 0
    for x, c in zip(req, map(int, input().split())):
        ans += x * c

    print(ans)

if __name__ == "__main__":
    main()

この解説は gpt-5.5-high によって生成されました。

posted:
last update: