- Choose the invariant that makes a window valid or useful.
- Advance the right boundary and add the new element.
- Move the left boundary only as needed while maintaining the invariant and updating the answer.
Code notes
- 231 lines of Python from the credited upstream file abc281_e.py.
- The implementation visibly relies on sequence storage, ordered lookup.
- No explicit loop blocks detected.
Complexity
Confirm that neither pointer moves backwards; if so, the scan is usually linear apart from the window’s data-structure operations.
Check the problem constraints before deciding whether this complexity will pass.
Use this to learn the idea, then write your own version.
12 3 4import math5from bisect import bisect_left, bisect_right, insort6from typing import Generic, Iterable, Iterator, TypeVar, Union, List7T = TypeVar('T')8 9 10class SortedMultiset(Generic[T]):11 """Sorted multi set (set) in C++.12 13 See:14 https:qiita.com/tatyam/items/492c70ac4c955c05560215 https:github.com/tatyam-prime/SortedSet/blob/main/SortedMultiset.py16 """17 18 BUCKET_RATIO = 5019 REBUILD_RATIO = 17020 21 def _build(self, a=None) -> None:22 "Evenly divide `a` into buckets."23 if a is None:24 a = list(self)25 26 size = self.size = len(a)27 bucket_size = int(math.ceil(math.sqrt(size / self.BUCKET_RATIO)))28 self.a = [a[size * i bucket_size: size * (i + 1) bucket_size] for i in range(bucket_size)]29 30 def __init__(self, a: Iterable[T] = []) -> None:31 "Make a new SortedMultiset from iterable. / O(N) if sorted / O(N log N)"32 a = list(a)33 34 if not all(a[i] <= a[i + 1] for i in range(len(a) - 1)): 35 a = sorted(a) 36 37 self._build(a)38 39 def __iter__(self) -> Iterator[T]:40 for i in self.a:41 for j in i:42 yield j 43 44 def __reversed__(self) -> Iterator[T]:45 for i in reversed(self.a):46 for j in reversed(i):47 yield j48 49 def __len__(self) -> int:50 return self.size51 52 def __repr__(self) -> str:53 return "SortedMultiset" + str(self.a)54 55 def __str__(self) -> str:56 s = str(list(self))57 return "{" + s[1: len(s) - 1] + "}"58 59 def _find_bucket(self, x: T) -> List[T]:60 "Find the bucket which should contain x. self must not be empty."61 for a in self.a:62 if x <= a[-1]: 63 return a64 return a 65 66 def __contains__(self, x: T) -> bool:67 if self.size == 0:68 return False69 70 a = self._find_bucket(x)71 i = bisect_left(a, x) 72 return i != len(a) and a[i] == x73 74 def count(self, x: T) -> int:75 "Count the number of x."76 return self.index_right(x) - self.index(x)77 78 def add(self, x: T) -> None:79 "Add an element. / O(√N)"80 if self.size == 0:81 self.a = [[x]]82 self.size = 183 return84 85 a = self._find_bucket(x)86 insort(a, x) 87 self.size += 188 89 if len(a) > len(self.a) * self.REBUILD_RATIO:90 self._build()91 92 def discard(self, x: T) -> bool:93 "Remove an element and return True if removed. / O(√N)"94 if self.size == 0:95 return False96 97 a = self._find_bucket(x)98 i = bisect_left(a, x) 99 100 if i == len(a) or a[i] != x:101 return False102 103 a.pop(i)104 self.size -= 1105 106 if len(a) == 0:107 self._build()108 109 return True110 111 def lt(self, x: T) -> Union[T, None]:112 "Find the largest element < x, or None if it doesn't exist."113 for a in reversed(self.a):114 if a[0] < x: 115 return a[bisect_left(a, x) - 1] 116 return None117 118 def le(self, x: T) -> Union[T, None]:119 "Find the largest element <= x, or None if it doesn't exist."120 for a in reversed(self.a):121 if a[0] <= x: 122 return a[bisect_right(a, x) - 1] 123 return None124 125 def gt(self, x: T) -> Union[T, None]:126 "Find the smallest element > x, or None if it doesn't exist."127 for a in self.a:128 if a[-1] > x: 129 return a[bisect_right(a, x)] 130 return None131 132 def ge(self, x: T) -> Union[T, None]:133 "Find the smallest element >= x, or None if it doesn't exist."134 for a in self.a:135 if a[-1] >= x: 136 return a[bisect_left(a, x)] 137 return None138 139 def __getitem__(self, x: int) -> T:140 "Return the x-th element, or IndexError if it doesn't exist."141 if x < 0:142 x += self.size143 if x < 0:144 raise IndexError145 146 for a in self.a:147 if x < len(a):148 return a[x] 149 150 x -= len(a)151 raise IndexError152 153 def index(self, x: T) -> int:154 "Count the number of elements < x."155 ans = 0156 157 for a in self.a:158 if a[-1] >= x: 159 return ans + bisect_left(a, x) 160 ans += len(a)161 return ans162 163 def index_right(self, x: T) -> int:164 "Count the number of elements <= x."165 ans = 0166 167 for a in self.a:168 if a[-1] > x: 169 return ans + bisect_right(a, x) 170 ans += len(a)171 return ans172 173 174def main():175 import sys176 177 input = sys.stdin.readline178 179 n, m, k = map(int, input().split())180 a = list(map(int, input().split()))181 b = sorted(a[:m])182 left = SortedMultiset(b[:k])183 right = SortedMultiset(b[k:])184 summed = sum(b[:k])185 ans = [summed]186 187 188 189 for i in range(n - m):190 191 aj = a[i + m]192 left_max = left[~0]193 194 if aj <= left_max:195 left.add(aj)196 summed += aj197 else:198 right.add(aj)199 200 201 ai = a[i]202 203 if ai in left:204 left.discard(ai)205 summed -= ai206 else:207 right.discard(ai)208 209 210 while len(left) > k:211 left_max = left[~0]212 left.discard(left_max)213 summed -= left_max214 215 right.add(left_max)216 217 while len(right) > m - k:218 right_min = right[0]219 right.discard(right_min)220 221 left.add(right_min)222 summed += right_min223 224 ans.append(summed)225 226 print(*ans)227 228 229if __name__ == "__main__":230 main()231