Skip to content

Commit 214ead4

Browse files
committed
Refactor count_subsequences
1 parent 35642a8 commit 214ead4

5 files changed

Lines changed: 73 additions & 23 deletions

File tree

requirements.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
art==6.1
2+
cfgv==3.4.0
23
click==8.1.7
34
colorama==0.4.6
5+
distlib==0.3.9
6+
filelock==3.17.0
7+
identify==2.6.7
48
iniconfig==2.0.0
59
mypy==1.8.0
610
mypy-extensions==1.0.0
11+
nodeenv==1.9.1
712
packaging==23.2
813
pathspec==0.12.1
914
platformdirs==4.2.0
1015
pluggy==1.4.0
16+
pre_commit==4.1.0
1117
pytest==8.0.0
18+
PyYAML==6.0.2
1219
ruff==0.3.4
1320
typing_extensions==4.9.0
21+
virtualenv==20.29.2

src/f_scanline/README.md

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Задачи на сканирующую прямую
22

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

55
| Поле | Значение |
66
|-----------|----------------------------------------|
@@ -32,7 +32,7 @@
3232
1 0 0
3333
```
3434

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

3737
| Поле | Значение |
3838
|-----------|----------------------------------------|
@@ -66,7 +66,7 @@ l ≤ r ≤ 10^9,
6666
3 6
6767
```
6868

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

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

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

83+
Пример.
84+
85+
Вход:
86+
87+
```text
88+
5
89+
1 2 3 4 5
90+
```
91+
92+
Выход:
93+
94+
```
95+
1 2
96+
3 4
97+
5 6
98+
```
99+
83100
## D. Оптимальный выбор заявок
84101

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

117+
Пример.
118+
119+
Вход:
120+
121+
```text
122+
3
123+
1 3
124+
2 5
125+
5 6
126+
```
127+
128+
Выход:
129+
130+
```
131+
1 3
132+
5 6
133+
```
134+
100135
## E. Максимальная прибыль при планировании задач
101136

102137
| Поле | Значение |

src/g_prefix_sums/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696

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

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

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

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

144144
Дана последовательность `N` натуральных чисел. Рассматриваются все её непрерывные подпоследовательности длиной

src/g_prefix_sums/count_subsequences.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,33 @@ def count_subsequences_naive(k: int, a: list[int]) -> int:
1717
# O(n)
1818
def count_subsequences_ps(k: int, a: list[int]) -> int:
1919
n = len(a)
20-
# prefix_count[i] - количество префиксов с остатком i
21-
prefix_count = [0] * k
22-
count, s = 0, 0
23-
# Заполняем очередь первыми 4 префиксами
24-
queue: deque[int] = deque()
20+
# Число префиксных сумм с определенным остатком от деления на k будем хранить в массиве dp
21+
dp = [0] * k
22+
# Число подходящих подпоследовательностей
23+
count = 0
24+
# Текущая сумма
25+
s = 0
26+
# Считаем первые 4 префиксные суммы
27+
q: deque[int] = deque()
2528
for i in range(4):
2629
s += a[i]
27-
queue.append(s)
28-
# Подсчитываем ответ
30+
q.append(s)
31+
# Считаем ответ
2932
for i in range(4, n):
30-
# Добавляем новый элемент в сумму, теперь в подпоследовательности не менее 5 элементов
33+
# Добавляем элемент в сумму
3134
s += a[i]
32-
# Обновляем количество подходящих подпоследовательностей
35+
# Если сумма подходит сама по себе, увеличиваем счетчик на 1
3336
if s % k == 0:
3437
count += 1
35-
# Со всеми префиксами того же остатка, что и S можно составить новую подпоследовательность
36-
count += prefix_count[s % k]
37-
# Обрабатываем первый префикс в очереди: теперь его можно использовать для составления новых
38-
# подпоследовательностей.
39-
prefix_count[queue.popleft() % k] += 1
40-
# Кладем текущий префикс в очередь
41-
queue.append(s)
38+
# Считаем число подходящих подпоследовательностей.
39+
# 1. Чтобы S стала кратна K, нужно отрубить от неё префикс с таким же остатком.
40+
# Например, если K = 3, S = 10, S % K = 1. Тогда из S надо выкинуть префикс с остатком 1.
41+
# 2. Следовательно, число подходящих подпоследовательностей возрастает на число префиксов с остатком S % K,
42+
# так как каждый из них можно отрубить от S.
43+
count += dp[s % k]
44+
# После обработки суммы, мы начинаем учитывать первую в очереди префиксную сумму. Удаляем её из очереди
45+
# и увеличиваем счетчик префиксных сумм с таким же остатком на 1.
46+
dp[q.popleft() % k] += 1
47+
# Кладем в очередь текущую сумму
48+
q.append(s)
4249
return count

src/g_prefix_sums/null_exchange.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# O(n)
22
def null_exchange(a: list[int]) -> int:
33
count = 0
4-
# prefix_sums[i] - количество периодов, когда сумма транзакций равна i.
4+
# p[i] - количество периодов, когда сумма транзакций равна i.
55
p: dict[int, int] = {}
66
curr_sum = 0
77
for num in a:
@@ -14,5 +14,5 @@ def null_exchange(a: list[int]) -> int:
1414
if curr_sum in p:
1515
count += p[curr_sum]
1616
# Добавляем текущую сумму в словарь или увеличиваем ее счетчик на один
17-
p[curr_sum] = p.get(curr_sum, 0) + 1
17+
p[curr_sum] = (p[curr_sum] if curr_sum in p else 0) + 1
1818
return count

0 commit comments

Comments
 (0)