🎃
ABC263 D - Left Right Operation Python解答例
AtCoder Beginner Contest 263 D - Left Right OperationをPythonで解きます。
問題
問題文をAtCoderのページより引用します。
問題文
長さ
の整数列 N が与えられます。 A=(A_1,A_2,\ldots,A_N) あなたは以下の連続する操作をちょうど一度だけ行います。
- 整数
を選ぶ。 x\ (0\leq x \leq N) として x を選んだ場合何もしない。 0 として x 以上の整数を選んだ場合、 1 をそれぞれ A_1,A_2,\ldots,A_x で置き換える。 L - 整数
を選ぶ。 y\ (0\leq y \leq N) として y を選んだ場合何もしない。 0 として y 以上の整数を選んだ場合、 1 をそれぞれ A_{N},A_{N-1},\ldots,A_{N-y+1} で置き換える。 R 操作後の
の要素の総和として考えられる最小値を求めてください。 A 制約
1 \leq N \leq 2\times 10^5 -10^9 \leq L, R\leq 10^9 -10^9 \leq A_i\leq 10^9 - 入力は全て整数
解答例
セグメント木で高速化
となります。
簡単のため、
また、配列
と変形できます[2]。
ここで、
であるような配列
区間の最小値を高速に求めるデータ構造といえばセグメント木です。これを用いることで、各
実装例
Pythonのコード例を以下に示します。
上述した考察は1-indexedで考えられている一方で、プログラムでは0-indexedで考えなければならないことに注意します。
d.py
from typing import (
List,
TypeVar,
Callable,
Generic,
Iterator,
Union,
)
import sys
import itertools
sys.setrecursionlimit(1000000)
input = sys.stdin.readline
### セグメント木のクラス実装は長いので省略
def main():
# 入力受け取り
N, L, R = map(int, input().split())
A: List[int] = list(map(int, input().split()))
# Aの総和(x, yともに0のときの答え)を求める
S: int = sum(A)
# 累積和を求める。1-indexedにしておくと何かと便利だったりする
C: List[int] = [0] + list(itertools.accumulate(A))
# 配列Dを計算する。こちらも1-indexed。
D: List[int] = [C[y] - R * y for y in range(N + 1)]
# 配列Dをもとに区間最小を求めるセグメント木を構築する。
seg = SegmentTree[int](min, lambda: 1 << 60, D)
# 各xについて値を計算し、最小値を求める。
answer: int = S
for x in range(N + 1):
answer = min(answer, R * N + L * x - C[x] + seg[x : N + 1])
# 答えの出力
print(answer)
if __name__ == "__main__":
main()
Discussion