Найти тему

Задача 532. Трамвай

Осталась одна задача первого тура регионального этапа Всероссийской олимпиады школьников по информатике 2009 года, которая ещё не разобрана на этом канале. Давайте закроем и её:

Условие задачи с сайта acmp.ru
Условие задачи с сайта acmp.ru

Довольно серьёзная сложность, приличные входные данные и интересная история.

Первое, что необходимо понять, это как среди двух человек выбрать того, кто будет сидеть. Представим двух пассажиров Alice и Bob. Выгодно, чтобы Alice сидела, если выполняется следующее неравенство:

-2

С таким условием работать неудобно, потому что придётся сравнивать всех пассажиров попарно. Но если все слагаемые с Alice собрать в одной стороне, а с Bob - в другой:

-3

Получается приятное неравенство. То есть можно каждого пассажира независимо оценить и на основе этих оценок составить приоритет на посадку: выгоднее посадить тех, у кого разница a и b максимальна.

Второе, что необходимо понять, это как хранить пассажиров. Мы уже знаем, что достаточно знать лишь одно число (разницу), но нам нужны операции "добавить пассажира", "удалить пассажира" и понимание сидит он или стоит.

Предлагаю пойти простым путём и воспользоваться стандартной структурой данных set, а точнее multiset (так как пассажиры могут иметь одинаковый приоритет), а ещё точнее - парой multiset'ов (отдельно для тех кто стоит и сидит). Благодаря раздельному хранению мы сможем точно отслеживать количество сидящих пассажиров, а благодаря упорядоченности данных во множествах быстро проверять надо ли посадить лучшего из стоящих.

Организуем для всего этого класс:

Класс Трамвай
Класс Трамвай

Для множества stand задал компаратор greater, чтобы элементы хранились в порядке убывания, потому что мне нужен доступ к самому большому из них. По условию задачи m - количество сидячих мест в трамвае, а в profit - буду поддерживать текущий уровень удовлетворения, изменяя его при добавлении и удалении пассажиров.

Напишем метод добавления нового пассажира:

Метод добавления нового пассажира
Метод добавления нового пассажира

Сначала мы его садим, увеличивая профит, но потом делаем проверку, что количество мест достаточно и нет такой ситуации, что пассажиру удобнее стоять. И если что-то из этого не выполняется, то ставим самого неприбыльного с точки зрения удовлетворения пассажира (это, вполне может быть не тот, которого мы добавили).

Процедура удаления немного сложнее, потому что надо сначала найти положение удаляемого пассажира:

Метод удаления пассажира
Метод удаления пассажира

Если пассажир сидел, то мы его удалям, уменьшаем профит и проверяем, стоит ли кого-нибудь посадить на его место. Если же пассажир изначально стоял, то просто удаляем его.

Посмотрим на реализацию метода move, который использовали при добавлении и удалении:

Метод move для изменения положения пассажира
Метод move для изменения положения пассажира

Его пришлось сделать шаблонным, так как сигнатуры множеств отличаются. Реализация очень простая: удаляем из from, добавляем в to. Возвращаем значение элемента, который переложили, чтобы можно было пересчитать профит.

Последний метод нашего класса - это получение текущего уровня удовлетворения:

Метод получения уровня удовлетворения
Метод получения уровня удовлетворения

Имея такой класс, достаточно промоделировать действия, описанные во входных данных. Ничего, кроме библиотеки ввода-вывода и set нам не понадобится:

Подключение библиотек
Подключение библиотек

Считаем все входные данные и сформируем из них два множества входящих и выходящих пассажиров. Для каждого из них будем хранить номер остановки и параметры a и b:

Ввод входных данных
Ввод входных данных

Заведём трамвай нужного размера и переменную, в которой будем накапливать удовлетворение (тип long long, чтобы не было переполнения), и пройдёмся по всем остановкам:

Перебор всех остановок
Перебор всех остановок

Для каждой остановки посадим (и высадим) всех пассажиров, которым это надо, используя сформированные множества и тот факт, что они упорядочены сначала по номеру остановки:

Обработка пассажиров на текущей остановке
Обработка пассажиров на текущей остановке

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

Выводим ответ, и задача решена:

Вывод ответа
Вывод ответа

Замечу, что вместо множеств можно было бы использовать кучу (в бинарной куче константа меньше). Для ускорения также можно было обрабатывать пассажиров оптом: сначала всех удалить и добавить, а уже потом делать пересадки.

Предыдущий выпуск: Задача 531. Газон

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

Наука
7 млн интересуются