@@ -17,26 +17,33 @@ def count_subsequences_naive(k: int, a: list[int]) -> int:
1717# O(n)
1818def 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
0 commit comments