О чём эта статья
Серия «Стратегия победы» — про траекторию тренировки, а не про одну задачу. Берём одну технику и проходим её на трёх уровнях нарастающей сложности, явно фиксируя, что именно усложняется между ступенями. Тема этой статьи — префиксные суммы, одна из самых дешёвых по реализации и самых частых на полосах CF 1100–2000.
Большинство участников осваивает базовый шаблон префиксных сумм быстро — за пару задач. Сложнее становится, когда задача требует двумерных префиксов (с inclusion-exclusion) или когда префиксы становятся не самоцелью, а инструментом подсчёта — как в задачах «сколько подотрезков обладают свойством ». Эта статья показывает путь от базового шаблона к этому уровню применения, шаг за шагом.
Ядро техники
Префиксная сумма — это вспомогательный массив, в котором каждый элемент хранит сумму всех элементов исходного массива от начала до текущей позиции. Имея такой массив, ответ на любой запрос «сумма на отрезке » считается за одно вычитание: . Препроцессинг — , каждый запрос — .
Если есть отдельная статья-«тема» по префиксным суммам в серии algoritmicheskie-osnovy — там подробно разобраны выбор индексации, отличие включающей и полу-открытой версии, типичные ловушки на границах. Здесь мы пользуемся уже отработанным шаблоном.
Базовый шаблон (псевдокод)
прочитать массив a длины n
P[0] ← 0
для i от 0 до n-1:
P[i+1] ← P[i] + a[i]
на каждый запрос (l, r): // a[l..r] включительно
ответ ← P[r+1] - P[l]
Сложность базового шаблона: время, память.
Что мы будем усложнять по мере роста:
- Ступень 1 → ступень 2: одномерный массив превращается в двумерную сетку; одно вычитание заменяется на четыре с учётом формулы включений-исключений.
- Ступень 2 → ступень 3: вместо «считать сумму на отрезке» приходит обратная задача: «по какому свойству префиксной суммы найти пары , чтобы отрезок имел нужное свойство». Здесь префикс соединяется с хешмапом.
Это и есть смысл серии: не «три разные задачи на префиксы», а осознанный путь от прямого применения шаблона к его роли как кирпичика более сложных решений.
Ступень 1 — CF ~1200 (одномерный шаблон, запросы на отрезке)
Условие
Дан массив из целых чисел. Поступает запросов; каждый запрос — пара , . На каждый запрос нужно вывести сумму .
Ограничения. , .
Как применяется базовый шаблон
Лобовое решение — для каждого запроса пройти от до и просуммировать. Это операций. Не помещается.
Заведём префиксный массив длины с конвенцией , . Тогда сумма на отрезке — это (если индексация массива с единицы, как в условии). Препроцессинг — , каждый запрос — .
Разбор на примере
, . Префиксы:
Запросы:
- : . Проверка: ✓
- : . Проверка: ✓
- : . Проверка: ✓
Код решения
Сложность: .
Что закрыли
На этом уровне закрыли сам шаблон 1D-префиксов: индексацию с единицы или нуля, базовую формулу . На следующей ступени к одной оси добавится вторая, и одно вычитание расщепится на четыре.
Ступень 2 — CF ~1600 (двумерные префиксы и inclusion-exclusion)
Условие
Дана прямоугольная сетка с целыми числами . Поступает запросов; каждый запрос — четвёрка , , . На каждый запрос нужно вывести сумму чисел в подпрямоугольнике с верхним левым углом и нижним правым включительно.
Ограничения. , , .
Что меняется в шаблоне
- Состояние: было одно — индекс . Стало два — пара .
- Препроцессинг: было . Стало Формула — прямое применение принципа включений-исключений: «прямоугольник от до = верхняя полоса + левая полоса − дважды посчитанный квадрат + текущая клетка».
- Запрос: было . Стало Четыре слагаемых с чередованием знаков — те же включения-исключения, но в обратном направлении.
Этот блок — сердце ступени. Без него двумерные префиксы остаются «трюком, который надо запомнить», а не приёмом, который можно вывести самостоятельно в любой задаче с похожей геометрией.
Разбор на примере
Сетка :
1 2 3
4 5 6
7 8 9
Префиксы (с ):
Запрос : подпрямоугольник со значениями , сумма .
По формуле:
Совпадает.
Код решения
Сложность: . Память — при это long long, около МБ.
Что закрыли
Ступень 2 — умение расширить шаблон на осей. На двух осях получаем четыре слагаемых; на трёх (если когда-то понадобятся 3D-префиксы для подсчёта в объёме) — восемь, с тем же чередованием знаков. Это inclusion-exclusion в чистом виде: коэффициенты по подмножеству «выбранных осей».
Следующий шаг — выйти за рамки прямых диапазонных запросов. Префиксы становятся инструментом подсчёта: задача формулируется как «сколько отрезков обладают свойством », и префиксная сумма из вспомогательного массива превращается в ключ структуры данных.
Ступень 3 — CF ~2000 (prefix + hashmap, подсчёт подотрезков с заданной суммой)
Условие
Дан массив целых чисел и целое число . Найти количество подотрезков массива (непрерывных подмассивов ), у которых сумма равна ровно .
Ограничения. , .
Что меняется в шаблоне
- Структура данных: двумерного массива больше нет. Префиксы остались одномерные, но теперь они ключи хешмапа, а не индексы для прямого доступа.
- Интеграция с другой техникой: соединяются префиксные суммы и хеш-таблица. Свойство «сумма отрезка равна » переписывается как «», то есть «пара префиксов с разностью ». Подсчёт пар префиксов с заданной разностью — стандартная задача на хешмап: для каждого правого конца проверяем, сколько раз раньше встречалось значение .
- Доказательство: соответствие подотрезков и пар префиксов биективное. Каждый подотрезок задаёт пару , и наоборот, каждая пара с задаёт подотрезок . Поэтому подсчёт пар префиксов с разностью — это то же самое, что подсчёт подотрезков с суммой .
Ключевой момент — сдвиг конвенции: префикс был «суммой до позиции », теперь он «значение, которое мы хешируем». Содержательно — одно и то же, но взгляд меняется.
Разбор на примере
, , . Префиксы (с ): .
Идём слева направо. Для каждой позиции ищем, сколько раз раньше встречалось .
| Сколько раз встречалось до этого | Накопленный ответ | |||
|---|---|---|---|---|
| (это ) | ||||
| (это ) | ||||
| (это ) |
После каждого шага увеличиваем счётчик для в хешмапе. Важно: в начале мы кладём в хешмап одну запись , чтобы корректно обрабатывались отрезки, начинающиеся с первого элемента (когда , разность с ).
Ответ — . Проверка ручным перебором подотрезков с суммой :
- — позиции , сумма . Нет.
- — позиции , сумма . Да.
- — позиция , сумма . Да.
- — позиции , сумма . Да.
Три подотрезка, ответ совпадает.
Код решения
Сложность: в среднем (с учётом операций хеш-таблицы). Память: под хешмап.
Что закрыли
На этом уровне техника применяется в полную силу. Префиксные суммы стали не самоцелью, а переменной, по которой мы строим решение задачи о подотрезках. Свойство, по которому ищем подотрезки, можно поменять — и шаблон останется в силе:
- «Сумма равна » → → пары префиксов с разностью .
- «Сумма делится на » → → пары префиксов с одинаковым остатком.
- «Сумма » при положительных значениях → отсортированные префиксы + бинпоиск или two pointers.
- «XOR-сумма равна » → пары префиксов с XOR равным → хешмап по XOR-префиксам.
Следующий шаг — выход за рамки техники: задачи, где префиксная сумма — лишь один из элементов; нужны DP или структуры данных поверх неё.
Что нужно держать в голове при переходе между ступенями
| Ступень | CF | Ключевое состояние | Ключевое усложнение vs предыдущая |
|---|---|---|---|
| 1 | ~ | — линейный массив сумм | — |
| 2 | ~ | — двумерный массив | inclusion-exclusion: четыре слагаемых вместо двух |
| 3 | ~ | как ключ хеш-таблицы | подсчёт пар префиксов с разностью |
Эта таблица — «карта местности» для тренировки. Её имеет смысл держать под рукой в первые – недели прохождения этой полосы. Любую задачу на префиксы можно отнести к одной из трёх категорий, и шаблон применять соответствующий.
Типичные ловушки на каждой ступени
- Ступень 1: путаница «включающий» и «полу-открытый» правый конец. В одной строке кода
P[r + 1] - P[l](правый конец включительно), в другой —P[r] - P[l](правый конец исключительно). Симптом — off-by-one на коротких отрезках. Лекарство — одна конвенция на всю задачу. - Ступень 2: путаница строк и столбцов. Формула с четырьмя слагаемыми требует строгого порядка осей. Если перепутать и , на симметричных примерах решение «случайно» проходит, на несимметричных — WA. Лекарство — рисовать формулу на бумаге перед написанием кода.
- Ступень 3: забытая
cnt[0] = 1. Если не учесть «пустой префикс» в начале, потеряем подотрезки, начинающиеся с первого элемента. Симптом — ответ меньше эталона ровно на число таких подотрезков. Лекарство — выработать рефлекс: первая строка после объявления хешмапа — увеличить счётчик для нулевого префикса. - Ступень 3:
unordered_mapпротив анти-хеш-атак. На Codeforces бывают тесты, специально сконструированные противunordered_map<long long, ...>со стандартным хешем. Лекарство — кастомный хеш с рандомным сидом илиmap<long long, ...>(логарифмический, иногда чуть быстрее на адверсариальных тестах). - Все ступени:
intпод суммы. , — сумма до ,intпереполнится.long longв C++ обязателен, в Python автоматически.
План тренировки
Практический чек-лист:
- Решить ступень 1 самостоятельно (без подсмотра кода). Цель — отработать индексацию и формулу до автоматизма.
- Решить – задач полосы CF ~ на одномерные префиксы. На Codeforces можно искать по тегу
dp+ сложности –, фильтровать по формулировкам «сумма на отрезке», «диапазонный запрос». - Перейти к ступени 2. Если застреваем более минут — открыть разбор в этой статье. После — самостоятельно реализовать без подсмотра.
- После ступени 2 — – задач полосы CF ~– на двумерные префиксы. Часто формулируются как «максимальная сумма прямоугольника» (это уже Kadane 2D, но шаг построения префиксов в нём — обязательный).
- Ступень 3 — аналогично, но без жёсткого ограничения по времени. Это полоса CF ~–, разбираться имеет смысл медленно. Лучший способ закрепить — переформулировать самостоятельно несколько задач с других тегов («подсчёт подотрезков», «подсчёт пар индексов») через язык «префикс + хешмап» и убедиться, что схема ложится.
- Финал тренировки — попытаться решить смесь: задача, где одна часть — двумерные префиксы, другая — подсчёт через хешмап. Такие гибриды появляются в полосе CF ~+ и тренируют не саму технику, а переключение между ступенями внутри одной задачи.
Итого
- Тема: префиксные суммы — от диапазонных запросов к подсчёту подотрезков.
- Траектория: CF ~ → ~ → ~, с усложнением: одна ось → две оси (inclusion-exclusion) → префикс как ключ хешмапа.
- Ключевое умение: не просто знание формулы , а способность переформулировать задачу через язык префиксов: видеть «подотрезок с суммой » как «пара префиксов с разностью », «подматрица с суммой » как «четыре префикса, связанные формулой включений-исключений», и так далее.