Skip to content

Commit

Permalink
Refactor count_subsequences
Browse files Browse the repository at this point in the history
  • Loading branch information
everysoftware committed Feb 17, 2025
1 parent 35642a8 commit 214ead4
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 23 deletions.
8 changes: 8 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
art==6.1
cfgv==3.4.0
click==8.1.7
colorama==0.4.6
distlib==0.3.9
filelock==3.17.0
identify==2.6.7
iniconfig==2.0.0
mypy==1.8.0
mypy-extensions==1.0.0
nodeenv==1.9.1
packaging==23.2
pathspec==0.12.1
platformdirs==4.2.0
pluggy==1.4.0
pre_commit==4.1.0
pytest==8.0.0
PyYAML==6.0.2
ruff==0.3.4
typing_extensions==4.9.0
virtualenv==20.29.2
41 changes: 38 additions & 3 deletions src/f_scanline/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Задачи на сканирующую прямую

## A. Посчитать отрезки, покрывающие точку
## A. Посчитать отрезки

| Поле | Значение |
|-----------|----------------------------------------|
Expand Down Expand Up @@ -32,7 +32,7 @@
1 0 0
```

## B. Минимальное покрытие точками
## B. Покрытие отрезков

| Поле | Значение |
|-----------|----------------------------------------|
Expand Down Expand Up @@ -66,7 +66,7 @@ l ≤ r ≤ 10^9,
3 6
```

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

| Поле | Значение |
|-----------|----------------------------------------|
Expand All @@ -80,6 +80,23 @@ x_i — координаты точек.

Формат вывода. Минимальное число m отрезков длины 1, необходимых для покрытия всех точек.

Пример.

Вход:

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

Выход:

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

## D. Оптимальный выбор заявок

| Поле | Значение |
Expand All @@ -97,6 +114,24 @@ x_i — координаты точек.
Формат вывода.
Выведите выбранные заявки.

Пример.

Вход:

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

Выход:

```
1 3
5 6
```

## E. Максимальная прибыль при планировании задач

| Поле | Значение |
Expand Down
4 changes: 2 additions & 2 deletions src/g_prefix_sums/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@

Пиксель `1`, стоящий на позиции `(3, 2)` при размере фильтра `1` размоется до:

`(1 + 4 + 3 + 2 + 2 + 5 + 5 + 5 + 6) // 9 = 29 // 9 = 3`
`(2 + 2 + 5 + 3 + 1 + 5 + 3 + 3 + 5) // 9 = 29 // 9 = 3`

Формат ввода.
На вход подаётся матрица пикселей изображения размера N x M (1 <= N, M <= 1000) и размер фильтра K (1 <= K <= 100).
Expand Down Expand Up @@ -138,7 +138,7 @@

| Поле | Значение |
|-----------|-------------------------------|
| Сложность | Средняя |
| Сложность | Сложная |
| Источник | https://kompege.ru/task, 2363 |

Дана последовательность `N` натуральных чисел. Рассматриваются все её непрерывные подпоследовательности длиной
Expand Down
39 changes: 23 additions & 16 deletions src/g_prefix_sums/count_subsequences.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,33 @@ def count_subsequences_naive(k: int, a: list[int]) -> int:
# O(n)
def count_subsequences_ps(k: int, a: list[int]) -> int:
n = len(a)
# prefix_count[i] - количество префиксов с остатком i
prefix_count = [0] * k
count, s = 0, 0
# Заполняем очередь первыми 4 префиксами
queue: deque[int] = deque()
# Число префиксных сумм с определенным остатком от деления на k будем хранить в массиве dp
dp = [0] * k
# Число подходящих подпоследовательностей
count = 0
# Текущая сумма
s = 0
# Считаем первые 4 префиксные суммы
q: deque[int] = deque()
for i in range(4):
s += a[i]
queue.append(s)
# Подсчитываем ответ
q.append(s)
# Считаем ответ
for i in range(4, n):
# Добавляем новый элемент в сумму, теперь в подпоследовательности не менее 5 элементов
# Добавляем элемент в сумму
s += a[i]
# Обновляем количество подходящих подпоследовательностей
# Если сумма подходит сама по себе, увеличиваем счетчик на 1
if s % k == 0:
count += 1
# Со всеми префиксами того же остатка, что и S можно составить новую подпоследовательность
count += prefix_count[s % k]
# Обрабатываем первый префикс в очереди: теперь его можно использовать для составления новых
# подпоследовательностей.
prefix_count[queue.popleft() % k] += 1
# Кладем текущий префикс в очередь
queue.append(s)
# Считаем число подходящих подпоследовательностей.
# 1. Чтобы S стала кратна K, нужно отрубить от неё префикс с таким же остатком.
# Например, если K = 3, S = 10, S % K = 1. Тогда из S надо выкинуть префикс с остатком 1.
# 2. Следовательно, число подходящих подпоследовательностей возрастает на число префиксов с остатком S % K,
# так как каждый из них можно отрубить от S.
count += dp[s % k]
# После обработки суммы, мы начинаем учитывать первую в очереди префиксную сумму. Удаляем её из очереди
# и увеличиваем счетчик префиксных сумм с таким же остатком на 1.
dp[q.popleft() % k] += 1
# Кладем в очередь текущую сумму
q.append(s)
return count
4 changes: 2 additions & 2 deletions src/g_prefix_sums/null_exchange.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# O(n)
def null_exchange(a: list[int]) -> int:
count = 0
# prefix_sums[i] - количество периодов, когда сумма транзакций равна i.
# p[i] - количество периодов, когда сумма транзакций равна i.
p: dict[int, int] = {}
curr_sum = 0
for num in a:
Expand All @@ -14,5 +14,5 @@ def null_exchange(a: list[int]) -> int:
if curr_sum in p:
count += p[curr_sum]
# Добавляем текущую сумму в словарь или увеличиваем ее счетчик на один
p[curr_sum] = p.get(curr_sum, 0) + 1
p[curr_sum] = (p[curr_sum] if curr_sum in p else 0) + 1
return count

0 comments on commit 214ead4

Please sign in to comment.