Задача 3. Борьба с рутиной

Автор:Центральная предметно-методическая комиссия   Ограничение времени:1 сек
Входной файл:Стандартный вход   Ограничение памяти:512 Мб
Выходной файл:Стандартный выход  
Максимальный балл:100  

Условие

Важным элементом повышения эффективности работы сотрудников является борьба с рутиной. Построим математическую модель разнообразия типов заданий, выполняемых сотрудником в компании.

Рассмотрим работу сотрудника в течение n последовательных рабочих дней. Будем считать, что каждый день сотрудник выполняет ровно один тип заданий, обозначим тип заданий, выполняемый сотрудником в i-й день, целым числом ai.

Для оценки рутинности работы сотрудника будем использовать следующую характеристику. Зафиксируем целое число d и рассмотрим все отрезки из d подряд идущих рабочих дней. Для каждого такого отрезка найдём количество различных типов заданий, которые работник выполнял на протяжении этих дней, и просуммируем эти значения. Полученную величину обозначим как Sd и будем называть её d-разнообразием. Чем d-разнообразие выше, тем больше различных типов заданий выполнял сотрудник. Профилем вариативности сотрудника будем называть массив значений [S1, S2, …, Sn].

Требуется написать программу, которая по заданной последовательности a1, a2, …, an типов выполняемых сотрудником заданий вычисляет его профиль вариативности.

Формат входных данных

В первой строке находится единственное целое число n  — количество последовательных рабочих дней, которые необходимо проанализировать (1 ≤ n ≤ 2 ⋅ 105).

Во второй строке находится n целых чисел a1, a2, …, an  — типы заданий, которое выполнял сотрудник (1 ≤ ai ≤ 109).

Формат выходных данных

Выведите n целых чисел: S1, S2, …, Sn.

Ограничения

1 ≤ ai ≤ 109

1 ≤ n ≤ 2 ⋅ 105

Система оценивания

Баллы за каждую подзадачу начисляются только в случае, если все тесты для этой подзадачи и необходимых подзадач успешно пройдены.

Подзадача Баллы Ограничения Необходимые подзадачи Информация о проверке
112 1 ≤ n ≤ 50, 1 ≤ ai ≤ 50первая ошибка
2101 ≤ n ≤ 50, 1 ≤ ai ≤ 1091первая ошибка
3101 ≤ n ≤ 500, 1 ≤ ai ≤ 1091,2первая ошибка
4121 ≤ n ≤ 5000, 1 ≤ ai ≤ 50001первая ошибка
5101 ≤ n ≤ 5000, 1 ≤ ai ≤ 1091 - 4первая ошибка
616 1 ≤ n ≤ 2 ⋅ 105, 1 ≤ ai ≤ 501первая ошибка
730 1 ≤ n ≤ 2 ⋅ 105, 1 ≤ ai ≤ 1091 - 6первая ошибка

Замечание

Рассмотрим, как вычисляются значения Sd в первом примере.

1-разнообразие: необходимо просуммировать количество различных типов заданий, выполняемых сотрудником по всем отрезкам, состоящим из одного дня.

Отрезок дней Типы заданий Количество различных
1 - 1 1 1
2 - 2 3 1
3 - 3 2 1
4 - 4 1 1
5 - 5 2 1

Значение 1-разнообразия равно S1 = 1 + 1 + 1 + 1 + 1 = 5.


2-разнообразие: необходимо просуммировать количество различных типов заданий, выполняемых сотрудником по всем отрезкам, состоящим из двух дней.

Отрезок дней Типы заданий Количество различных
1 - 2 1, 3 2
2 - 3 3, 2 2
3 - 4 2, 1 2
4 - 4 1, 2 2

Значение 2-разнообразия равно S2 = 2 + 2 + 2 + 2 = 8.


3-разнообразие: необходимо просуммировать количество различных типов заданий, выполняемых сотрудником по всем отрезкам, состоящим из трех дней.

Отрезок дней Типы заданий Количество различных
1 - 3 1, 3, 2 3
2 - 4 3, 2, 1 3
3 - 5 2, 1, 2 2

Значение 3-разнообразия равно S3 = 3 + 3 + 2 = 8.


4-разнообразие: необходимо просуммировать количество различных типов заданий, выполняемых сотрудником по всем отрезкам, состоящим из четырех дней.

Отрезок дней Типы заданий Количество различных
1 - 4 1, 3, 2, 1 3
2 - 5 3, 2, 1, 2 3

Значение 4-разнообразия равно S4 = 3 + 3 = 6.


5-разнообразие: необходимо просуммировать количество различных типов заданий, выполняемых сотрудником по всем отрезкам, состоящим из пяти дней.

Отрезок дней Типы заданий Количество различных
1 - 5 1, 3, 2, 1, 2 3

Значение 5-разнообразия равно S5 = 3.


Примеры тестов

Стандартный вход Стандартный выход
1
5
1 3 2 1 2
5 8 8 6 3 
2
3
10 10 10
3 2 1 

Разбор

В подзадаче 1 для этого можно использовать массив элементов типа bool, отмечая встретившиеся значения, в подзадаче 2 встретившиеся значения можно сложить, например, в std::set, либо в массив, отсортировать и найти число различных значений. Наконец, отметим, что поскольку n ≤ 50, можно обойтись даже без сортировки, для каждого элемента проверяя, не встречался ли он раньше.

Решение с std::set при аккуратное реализации может также пройти подзадачу 3, альтернатива  — отсортировать значения на отрезке с помощью std::sort и посчитать количество различных значений.

Улучшим это решение.

Зафиксируем длину отрезка d и посмотрим для каждого числа c в массиве то, в скольких отрезках оно не встречается. Посмотрим на два соседних вхождения числа, если расстояние между ними x ≥ d, то существует ровно d − x + 1 отрезок, лежащий между ними. Просуммировав эту величину по всем парам соседних вхождений числа, а также между началом массива и первым числом и между последним числом и концом массива, получим количество отрезков, которые не включают в себя ни одно вхождение данного числа.

Обозначим эту величину за D(d, c). Тогда ответ для заданной длины отрезка  — это ((n − L + 1) − D(d,c)). Если посчитать эту сумму наивно, получим решение за O(n2), которое проходит подзадачи 3--5. Заметим, что для решения подзадачи 4 этим методом не требуется перебор значений, которые встречаются в массиве, можно перебирать значения от 1 до 5000.

Для получения полного решения этим методом нужно избавиться от суммирования по c для каждого d. Для этого запишем все значения расстояний между соседними вхождениями c в один массив a для всех c. Тогда c((n − L + 1) − D(d,c)) = imax(a[i] − d + 1,0).

Чтобы посчитать эту сумму можно найти префиксные суммы массива ai и двоичным поиском находить позицию, где max(a[i] − d + 1,0) начинает равняться 0 для данного d. Альтернативно можно заметить, что эта позиция только растёт при росте d.


0.074s 0.011s 13