Skip to content

Commit

Permalink
Refactor prizes_hard
Browse files Browse the repository at this point in the history
  • Loading branch information
everysoftware committed Feb 3, 2025
1 parent bc3f1f0 commit 35642a8
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 53 deletions.
10 changes: 5 additions & 5 deletions src/e_two_pointers/prizes_2s.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# O(n)
def prizes_hard(prize_positions: list[int], k: int) -> int:
n = len(prize_positions)
# Максимальное число призов на подмассиве prize_positions[:i]
dp = [0] * (n + 1)
# Максимальное число призов до i-й позиции
dp = [0] * n
low, ans = 0, 0
for high in range(n):
# Сдвигаем левый указатель, пока не удовлетворим условие
Expand All @@ -11,7 +11,7 @@ def prizes_hard(prize_positions: list[int], k: int) -> int:
# Считаем число призов в текущем отрезке
curr = high - low + 1
# Обновляем максимальное число призов
dp[high + 1] = max(dp[high], curr)
# Сочетаем с лучшим отрезком до текущего
ans = max(ans, dp[low] + curr)
dp[high] = max(dp[high - 1] if high > 0 else 0, curr)
# Сочетаем с лучшим отрезком до текущего отрезка
ans = max(ans, (dp[low - 1] if low > 0 else 0) + curr)
return ans
17 changes: 17 additions & 0 deletions src/f_scanline/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,23 @@ l ≤ r ≤ 10^9,
Формат вывода. Выведите оптимальное число m точек и сами m точек. Если таких множеств точек
несколько, выведите любое из них.

Пример.

Вход:

```text
3
1 3
2 5
4 6
```

Выход:

```
3 6
```

## C. Минимальное покрытие отрезками

| Поле | Значение |
Expand Down
2 changes: 1 addition & 1 deletion src/f_scanline/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from src.f_scanline.points_and_segments import (
from src.f_scanline.count_segments import (
count_segments_bisect,
count_segments,
)
Expand Down
54 changes: 54 additions & 0 deletions src/f_scanline/count_segments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import bisect


# O((n + m)log(n + m))
def count_segments(segments: list[tuple[int, int]], points: list[int]) -> list[int]:
m = len(points)
# Формируем список событий
events: list[tuple[int, int, int]] = []
for x0, x1 in segments:
# Начало отрезка - вклад в ответ +1
events.append((x0, 1, 0))
# Конец отрезка - вклад в ответ -1
events.append((x1, -1, 0))
for i, x in enumerate(points):
# Появление точки - вклад в ответ 0, записываем индекс (он нужен для сохранения порядка в result)
events.append((x, 0, i))
# Сортируем события: по возрастанию X координаты, по убыванию вклада в ответ
events.sort(key=lambda entry: (entry[0], -entry[1]))
# Считаем ответ. result[i] - ответ для i-й точки
result = [0] * m
# Текущий ответ (сколько отрезков пересекает точка)
count = 0
for _, contribute, i in events:
# Если это отрезок, меняем ответ в соответствии с вкладом в него
if contribute != 0:
count += contribute
# Если это точка, то записываем её ответ
else:
result[i] = count
return result


# O(n log n + m log n) = O((n + m) log n)
def count_segments_bisect(segments: list[tuple[int, int]], points: list[int]) -> list[int]:
# Формируем список начал и концов отрезка
x0_all, x1_all = [], []
for x0, x1 in segments:
x0_all.append(x0)
x1_all.append(x1)
# Сортируем события
x0_all.sort()
x1_all.sort()
# Вычисляем ответ
result = []
for x in points:
# Сколько отрезков начинаются в точке x или левее
high = bisect.bisect_right(x0_all, x)
# Сколько отрезков заканчиваются строго левее точки x
low = bisect.bisect_left(x1_all, x)
# Количество отрезков, пересекающих точку
count = high - low
# Добавляем ответ
result.append(count)
return result
17 changes: 10 additions & 7 deletions src/f_scanline/min_set_of_points.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
# O(n log n)
def min_set_of_points(segments: list[tuple[int, int]]) -> list[int]:
n = len(segments)
# Сортируем отрезки по правому концу.
segments.sort(key=lambda x: x[1])
cover = []
# Сортируем отрезки по правой границе
segments.sort(key=lambda entry: entry[1])
i = 0
# Покрытие точками
cover = []
# Пока не покроем все отрезки
while i < n:
segment = segments[i]
cover.append(segment[1])
# Пропускаем пересекающиеся отрезки.
while i < n and segments[i][0] <= segment[1]:
# Добавляем минимальный конец отрезка в покрытие
x = segments[i][1]
cover.append(x)
# Пропускаем отрезки, покрытые точкой x
while i < n and segments[i][0] <= x:
i += 1
return cover
40 changes: 0 additions & 40 deletions src/f_scanline/points_and_segments.py

This file was deleted.

0 comments on commit 35642a8

Please sign in to comment.