editorial で紹介されている解法は だが,別解として と の 2 通りで解けたので ( の制約だとあまり差は出なさそう).
問題
解法
基本的な考え方は,初めに訪れる焼肉店 を降順に動かしながら差分を計算するというもの.
焼肉店 で終了する場合の最適値と焼肉店 で終了する場合の最適値の差分 を管理する. を動かしたときに, を高速に更新することが出来れば, を固定した場合の最適値は として求まる.これは毎回愚直に求めても全体で である.
とする.
の更新には, 本の stack を用いる. 番目の stack を とし, には のペアを積んでいく.ただし, の場合は積まないものとする.
を動かすごとに,各 に対して を以下の手続きにより更新する.
- とする.
- が空でなく,かつ であるならば,3 へ.そうでなければ,4 へ.
- の先頭 を pop する. ならば, として 2 へ.そうでなければ, に を push して 4 へ.
- に を push する.
つまるところ, であるような に対応するペアを から取り除き,初めて となる に対してその差分を更新している.
に関しては, が pop される度に と更新し,push される度に と更新する.また,移動距離を考慮して とする必要がある.
および の更新にかかる計算量は一見すると であるが,実は となっている.
[tex: O(MN)] の理由
各 に対して更新回数が全体で となっていることが言えればよい.
手続きの 3. において push が起こる回数は,各 に対して高々 回 *1 で,合計 回である.また, 4. において push が起こる回数も各 に対して高々 回である.従って, への push が起こる回数は 回である. から pop する回数は への push の回数以下なので,pop の回数も である.
以上より,各 に対して,手続き全体にかかる計算量は である.
および の更新に , を求めるのに かかるので,結局全体 でこの問題が解けた.
上の解法において, の定義を累積和に変更して区間 add,区間 max の遅延セグ木に載せれば となる.
実装 (Python)
def solve(): N, M = map(int, input().split()) A = [*map(int, input().split())] B = [[*map(int, input().split())] for _ in range(N)] d = [0] * N S = [[] for _ in range(M)] ans = 0 for l in reversed(range(N)): if l < N - 1: d[l + 1] -= A[l] for j in range(M): v = B[l][j] while S[j] and v: x, y = S[j].pop() d[x] -= y if v >= y: v -= y else: S[j].append((x, y - v)) d[x] += y - v break S[j].append((l, B[l][j])) d[l] += B[l][j] d_sum = 0 for r in range(l, N): d_sum += d[r] ans = max(ans, d_sum) return ans if __name__ == '__main__': print(solve())
*1:push が起こると即座に 4. へと移り,更新が終了するため