Редакция для Запросы числа чётных на отрезке
Submitting an official solution before solving the problem yourself is a bannable offence.
1. Идея
Нужно много раз отвечать на вопрос: сколько чётных чисел находится на отрезке l..r.
Если для каждого запроса отдельно проходить по всему отрезку, то в худшем случае получится слишком долго: до 2 * 10^5 запросов, и каждый может быть длины до 2 * 10^5.
Поэтому удобно заранее посчитать массив префиксных сумм:
- для каждой позиции хранить, сколько чётных чисел встретилось с начала массива до этой позиции.
Тогда ответ на любой запрос можно получить за O(1).
2. Наблюдения
Для задачи важно не само значение числа, а только чётное оно или нет.
Каждое число можно заменить на индикатор:
1, если число чётное;0, если число нечётное.
Например, массив
0 1 -1 2 -2
превращается в
1 0 0 1 1.Если построить префиксную сумму
pref, гдеpref[i]— количество чётных среди первыхiэлементов, то:pref[r]— число чётных на префиксе1..r;pref[l - 1]— число чётных на префиксе1..l-1.
Тогда на отрезке
l..rчётных будет:pref[r] - pref[l - 1].Отрицательные числа тоже корректно проверяются на чётность. Например,
-2— чётное,-1— нечётное.
3. Алгоритм
- Считать
n. - Считать массив из
nчисел. - Построить массив
prefдлиныn + 1:pref[0] = 0;- для
iот1доn:- если
a[i - 1]чётное, прибавить1; - иначе прибавить
0.
- если
- Считать
q. - Для каждого запроса
l, rвывести:pref[r] - pref[l - 1].
4. Почему это работает
Пусть pref[i] — количество чётных чисел среди первых i элементов массива.
Тогда:
pref[r]считает все чётные на позициях от1доr;pref[l - 1]считает все чётные на позициях от1доl - 1.
Если из первого количества вычесть второе, то останутся только чётные числа на позициях от l до r.
То есть ответ на запрос равен:
pref[r] - pref[l - 1].
Это верно для любого запроса, потому что префиксные суммы как раз позволяют выделять сумму или количество на любом подотрезке вычитанием двух префиксов.
5. Сложность
- Построение префиксного массива:
O(n). - Ответ на каждый запрос:
O(1). - Всего запросов
q, значит общая сложность: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] + (x % 2 == 0 ? 1 : 0);
}
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] + (1 if a[i - 1] % 2 == 0 else 0)
q = int(input())
for _ in range(q):
l, r = map(int, input().split())
print(pref[r] - pref[l - 1])
Комментарии