Комбо-удары на сумму K

тема: Префиксные суммы · уровень: средний

Условие

В игре есть полоса комбо из N ударов подряд. За i‑й удар дают a_i очков (может быть и штраф — отрицательное число). Игрок выбирает один непрерывный отрезок ударов и получает сумму очков на этом отрезке.

Тренер записал целевое число K и хочет знать: сколько разных непрерывных отрезков дают ровно K очков.

Нужно посчитать количество пар (l, r), где 1 ≤ l ≤ r ≤ N и a_l + a_{l+1} + ... + a_r = K.

Формат ввода

Первая строка: два целых числа N и K. Вторая строка: N целых чисел a_1, a_2, ..., a_N.

Формат вывода

Выведите одно целое число — количество непрерывных отрезков с суммой K.

Ограничения

Пример

Ввод:

5 3
1 2 1 -1 2

Вывод:

3

Пояснение: подходят отрезки [1..2], [2..4], [3..5].

Как решать — идея подхода

Приём: Префиксные суммы + частоты в словаре

Ключевое наблюдение: сумма на отрезке [l..r] равна s[r] - s[l-1], где s[i] — префиксная сумма первых i элементов (s[0]=0). Тогда условие a[l]+...+a[r]=K превращается в s[l-1] = s[r] - K.

Значит, для каждого правого конца r достаточно знать, сколько раз раньше встречалась префиксная сумма s[r]-K. Это удобно считать на лету словарём (hash map): ключ — значение префиксной суммы, значение — сколько раз оно уже было.

Почему это работает: мы перебираем r слева направо, и каждый раз добавляем число подходящих l через уже накопленные префиксы. Отрицательные числа не мешают, поэтому метод надёжнее «двух указателей».

План:

Сложность: O(N) по времени и O(N) по памяти (в худшем случае все префиксные суммы разные).

Частая ошибка: забыть cnt[0]=1 или перепутать порядок обновлений (сначала считать вклад в ответ, потом увеличивать cnt[s]), иначе отрезки, начинающиеся с 1, и/или нулевой длины будут учтены неверно.

Разберись руками

Есть 5 ударов подряд с очками: 1, 2, 1, -1, 2. Нужно понять, сколько разных непрерывных отрезков дают ровно 3 очка.

Идея: Сначала посчитать накопленные суммы слева направо. Потом сумму любого непрерывного отрезка не пересчитывать сложением, а получать как разность «накопленной суммы в конце отрезка» и «накопленной суммы перед его началом». Так можно быстро проверять, какие отрезки дают нужную сумму.

Решить задачу с автопроверкой на Python →

Куда дальше