Баланс в школьной столовой
Условие
В школьной столовой завели «дневник баланса» по дням: в какой-то день кто-то пополнил счёт (это плюс), а в какой-то списали за обеды (это минус). Классный руководитель часто спрашивает: «А какой итог был за дни с L по R включительно?»
Тебе нужно быстро отвечать на такие вопросы.
Формат ввода
В первой строке даны два целых числа n и q — число дней и число вопросов. Во второй строке даны n целых чисел a1, a2, ..., an — изменения баланса по дням. В следующих q строках даны пары целых чисел L R (1 ≤ L ≤ R ≤ n) — границы отрезка дней.
Формат вывода
Для каждого вопроса выведи одно целое число — сумму aL + a(L+1) + ... + aR.
Ограничения
- 2 ≤ n ≤ 16000
- 1 ≤ q ≤ 16000
- -1 000 000 ≤ ai ≤ 1 000 000
- 1 ≤ L ≤ R ≤ n
Пример
Ввод:
5 3
10 -7 2 0 5
1 3
2 5
4 4
Вывод:
5
0
0Как решать — идея подхода
Приём: Префиксные суммы
Ключевое наблюдение: сумму на отрезке L..R удобно получать не складыванием всех элементов, а «вычитанием лишнего» из накопленных сумм.
Заведём массив префиксных сумм pref, где pref[i] — сумма изменений за первые i дней (от 1 до i). Тогда сумма на любом отрезке L..R равна: pref[R] - pref[L-1]. Это работает, потому что в pref[R] сидит сумма 1..R, а в pref[L-1] — ровно то, что нужно убрать (1..L-1).
План решения:
- Прочитай
nиq, затем массивa[1..n]. - Создай
prefдлиныn+1, положиpref[0] = 0. - Для i от 1 до n посчитай
pref[i] = pref[i-1] + a[i]. - Для каждого запроса (L, R): выведи
pref[R] - pref[L-1].
Сложность: построение pref — O(n), каждый запрос — O(1), итого O(n + q) вместо O(n*q).
Частая ошибка: забыть про pref[0] = 0 и сдвиг индексов (особенно в Python со списками с 0). Формула именно pref[R] - pref[L-1], иначе запросы с L=1 ломаются.
Разберись руками
Есть 5 дней, каждый день баланс менялся: 10, -7, 2, 0, 5. Учитель спрашивает сумму изменений за разные куски дней (например, с 2-го по 5-й). Хочется отвечать, не складывая каждый раз заново.
- Сделай «накопленный итог» по дням. Стартовый баланс перед 1-м днём считаем 0. После каждого дня записывай новый итог.
- Вопрос 1 3: сумма за дни 1..3. Используй накопленные итоги: возьми итог на конце 3-го дня и вычти итог перед 1-м днём (это 0). Сколько получится?
- Вопрос 2 5: сумма за дни 2..5. Возьми итог на конце 5-го дня и вычти итог на конце 1-го дня. Какое число выйдет?
- Вопрос 4 4: сумма только за 4-й день. Возьми итог на конце 4-го дня и вычти итог на конце 3-го дня. Сколько?
Идея: Сначала один раз посчитай накопленные итоги по дням (сколько получилось всего к концу каждого дня). Потом для любого запроса про дни с L по R не складывай заново: возьми накопленный итог на конце R и вычти накопленный итог на конце дня перед L — останется ровно сумма внутри отрезка.
Решить задачу с автопроверкой на Python →
Куда дальше
- С нуля до олимпиады: маршрут — сколько занимает язык, какие приёмы нужны и к какому этапу это ведёт
- Вердикты судьи: WA, TLE, RE, PE, CE — что значит каждый код проверяющей системы и где искать причину
- Python на олимпиадах — где языка хватает с запасом, а где начинают значить лимиты — с замерами