Разбор
Интервал будем называть хорошим, если на нем находятся числа в промежутке включительно (то есть ).
Реализуем скользящее окно при помощи двух указателей и и будем его поддерживать так, чтобы текущий рассматриваемый интервал был хорошим, а интервал плохим.
Например, для следующей последовательности
интервалы и являются хорошими.
интервалы являются плохими.
Если , то расширяем текущий интервал до . Иначе сокращаем его до . Перед передвижением указателя выводим количество элементов, лежащих между и включительно. Оно равно .
Оценка сложности алгоритма линейная, то есть .
Пример
Рассмотрим движение указателей для приведенного примера.
Для заданного состояния , поэтому двигаем вперед указатель .
Теперь . Вперед следует двигать указатель . Однако перед его перемещением выводим количество элементов, лежащих между и включительно. Оно равно .
Двигаем вперед пока .
Теперь . Выводим ответ для (он равен ) и увеличиваем на .
Реализация алгоритма
Читаем входные данные.
scanf("%d", &n); for (i = 0; i < n; i++) scanf("%d", &a[i]);
Инициализируем указатели .
i = j = 0;
Двигаем указатели вперед пока для каждого значения не будет найден ответ.
while (i < n) // [i..j] {
Если (но при этом не вышло за границы массива, то есть ), то расширяем текущий интервал, увеличивая указатель .
if ((j < n) && (a[j] <= 2 * a[i])) j++; else {
При выводим ответ для индекса и увеличиваем на единицу.
printf("%d ", j - i); i++; } }
Реализация алгоритма — бинарный поиск, O(n log n)
Читаем входные данные.
scanf("%d", &n); v.resize(n); for (i = 0; i < n; i++) scanf("%d", &v[i]);
Для каждого индекса при помощи бинарного поиска ищем такое наибольшее значение индекса , что на интервале находятся числа от до , а . Количество чисел на интервале равно .
for (i = 0; i < n; i++) { x = upper_bound(v.begin(), v.end(), 2 * v[i]) - v.begin(); printf("%d ", x - i); }
Java реализация
import java.util.*; public class Main { public static void main(String[] args) { Scanner con = new Scanner(System.in); int n = con.nextInt(); int m[] = new int[n]; for(int i = 0; i < n; i++) m[i] = con.nextInt(); int i = 0, j = 0; while (i < n) // [i..j] { if ((j < n) && (m[j] <= 2 * m[i])) j++; else { System.out.print(j - i + " "); i++; } } con.close(); } }
Python реализация
Читаем входные данные.
n = int(input()) lst = list(map(int,input().split()))
Инициализируем указатели .
i = j = 0
Двигаем указатели вперед пока для каждого значения не будет найден ответ.
while (i < n): # [i..j]
Если (но при этом не вышло за границы массива, то есть ), то расширяем текущий интервал, увеличивая указатель .
if (j < n and lst[j] <= 2 * lst[i]): j += 1 else:
При выводим ответ для индекса и увеличиваем на единицу.
print(j - i, end=" "); i += 1
Python реализация — бинарный поиск, O(n log n)
from bisect import bisect_right
Читаем входные данные.
n = int(input()) v = list(map(int, input().split()))
Для каждого индекса при помощи бинарного поиска ищем такое наибольшее значение индекса , что на интервале находятся числа от до , а . Количество чисел на интервале равно .
for i in range(n): x = bisect_right(v, 2 * v[i]) print(x - i, end=" ")