Редакция для Сумма по чётным позициям на отрезке
Submitting an official solution before solving the problem yourself is a bannable offence.
1. Идея
В каждом запросе нужно найти сумму элементов массива на отрезке [l, r], но учитывать только те элементы, которые стоят на чётных позициях массива: 2, 4, 6, ....
Если для каждого запроса перебирать все позиции от l до r, получится слишком медленно: при больших n и q это может дать до O(nq) операций.
Поэтому нужно заранее подготовить такую структуру, которая позволит отвечать на каждый запрос за O(1). Для этого отлично подходят префиксные суммы.
2. Наблюдения
Пусть pref[i] — сумма элементов на чётных позициях среди первых i элементов массива.
Тогда:
- если позиция
iнечётная, тоpref[i] = pref[i - 1]; - если позиция
iчётная, тоpref[i] = pref[i - 1] + a[i].
Тогда сумма по чётным позициям на отрезке [l, r] равна:
pref[r] - pref[l - 1]
Почему это верно:
pref[r]содержит сумму всех элементов на чётных позициях от1доr;pref[l - 1]содержит сумму всех элементов на чётных позициях от1доl - 1;- если вычесть вторую сумму из первой, останутся только чётные позиции внутри
[l, r].
3. Алгоритм
- Считываем
n. - Считываем массив из
nчисел. - Строим массив префиксных сумм
prefдлиныn + 1.pref[0] = 0- для каждого
iот1доn:- сначала
pref[i] = pref[i - 1] - если
iчётное, добавляем значение текущего элемента
- сначала
- Считываем число запросов
q. - Для каждого запроса
(l, r)выводимpref[r] - pref[l - 1].
4. Почему это работает
Докажем корректность.
После построения массива pref[i] действительно хранит сумму всех a[j], где:
1 <= j <= ijчётно
Это верно по построению:
- база:
pref[0] = 0, сумма на пустом префиксе равна нулю; - переход:
- если
iнечётно, новый элемент не должен учитываться, значит сумма не меняется; - если
iчётно, новый элемент должен учитываться, значит прибавляемa[i].
- если
Теперь рассмотрим запрос [l, r].
pref[r] содержит сумму по всем чётным позициям до r, а pref[l - 1] — сумму по всем чётным позициям до позиции перед l. Значит их разность оставляет ровно чётные позиции из отрезка [l, r].
Следовательно, ответ вычисляется правильно.
5. Сложность
Построение префиксного массива:
O(n)
Ответ на каждый запрос:
O(1)
Итоговая сложность:
O(n + q)
Дополнительная память:
O(n)
6. Код на C++17
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n;
cin >> n;
vector<long long> pref(n + 1, 0);
for (int i = 1; i <= n; i++) {
long long x;
cin >> x;
pref[i] = pref[i - 1];
if (i % 2 == 0) {
pref[i] += x;
}
}
int q;
cin >> q;
for (int i = 0; i < q; i++) {
int l, r;
cin >> l >> r;
cout << pref[r] - pref[l - 1] << '\n';
}
return 0;
}
7. Код на Python 3
n = int(input())
a = list(map(int, input().split()))
pref = [0] * (n + 1)
for i in range(1, n + 1):
pref[i] = pref[i - 1]
if i % 2 == 0:
pref[i] += a[i - 1]
q = int(input())
for _ in range(q):
l, r = map(int, input().split())
print(pref[r] - pref[l - 1])
Комментарии