Всем Привет!

Меня зовут Максим и я очень давно хочу достичь рейтинга 3000. Я верю, что для этого мне надо научиться мыслить, как человек, у которого уже есть 3000 рейтинга. Очень часто в разборах пишут фразы "заметим, что..." или "докажем вот такой факт..." и дальше идет долгое доказательство этого факта. А то, каким образом я должен к этому факту прийти, как эта мысль должна зародиться у меня в голове, никто нигде не пишет. Я думаю, что не только у меня есть эта проблема, поэтому вместо того, чтобы ждать понятный разбор, я решил начать с себя. Именно поэтому, я решил написать пошаговый разбор, где я буду описывать ход своих мыслей и действий, которые позволяют мне придумать эти самые идеи.
Также, я создал группу по прокачке навыков спортивного программирования для людей с рейтингом 1200- , чтобы помочь им стать лучше и достигнуть рейтинга 1500+. Если хотите больше об этом узнать, рекомендую прочитать ЭТОТ ПОСТ или заполнить ФОРМУ. Эту группу я назвал Polaris в честь путеводной звезды. В Polaris ребята решают специально подобранные контесты под их уровень, дорешивают их с помощью пошаговых разборов, изучают новую теорию, решают специально подготовленные для них подводящие упражнения, а также получают подробные рекомендации на основе их участия в тренировочных контестах. Более того, специально для участников группы я делаю пошаговые разборы тех задач, которые интересны самим участникам. Также, в группе регулярно ведется обсуждение прошедших контестов, а в ближайшем будущем мы будем готовиться к предстоящим олимпиадам (как школьным, так и студенческим). Присоединяйтесь, я буду вам очень рад!
А теперь перейдем к самому разбору контеста. Но перед этим, я бы хотел ввести несколько правил чтения разбора для того, чтобы вы смогли получить максимум пользы от него.
- Перед чтением разбора задачи, убедитесь, что вы прочитали задачу, подумали над ней, извлекли из своей головы и записали/нарисовали максимальное количество идей и больше уже ничего не можете придумать.
- Во время чтения разбора, если в какой-то момент, какое-то предложение в разборе навело вас на новую мысль, перестаньте читать разбор и вернитесь к пункту (1), а именно продолжите с этого места генерировать новые идеи. Это очень важно.
- Если вы дочитали текст разбора до конца и не поняли, как решать задачу или остались вопросы, то их нужно обязательно задать в комментариях или спросить в Polaris. Там вам помогут я и ребята, кто справился с этой задачей. Также в этом случае, полезно прочитать код, который будет прикреплен к разбору.
- После того, как вы решили задачу, обязательно посмотрите код других участников и код с разбора. Возможно, он наведет вас на мысль о том, как можно было проще и быстрее реализовать решение задачи.
A. Разработка ИИ-проекта
Шаг 1Судя по всему, нужно аккуратно расписать формулы в соответствии с условием задачи. Предположим, что мы знаем, что ответ равен $$$T$$$. Какие на него есть условия, когда Никита не использует ИИ? Сколько строк кода напишут ребята?
Шаг 2Они напишут $$$T\cdot (x + y)$$$ строк кода и мы хотим, чтобы выполялось $$$T\cdot (x + y) \ge n$$$, тогда $$$T \ge \frac{n}{x+y}$$$. А что если они будут использовать ИИ?
Шаг 3Тогда они напишут $$$T\cdot x + (T-z)\cdot 10\cdot y$$$ строк. Какое тогда есть ограничение на $$$T$$$?
Шаг 4$$$T\cdot x + (T-z)\cdot 10\cdot y \ge n$$$, тогда $$$T\cdot(x+10y) \ge n + 10zy$$$, тогда $$$T \ge \frac{n + 10zy}{x+10y}$$$.
Шаг 5Выбираем максимум из двух выражений и округляем вверх.
Решение: 377920759
B. Различные расстояния
Шаг 1Какой самый простой случай можно рассмотреть?
Шаг 2Когда $$$n=2$$$. Как его решить?
Шаг 3Обозначим два числа за $$$X,Y$$$, тогда можно взять например такой ответ: "XYYXXYXY", тогда для $$$X$$$ расстояния образуют множество $$$(3,1,2)$$$, а у $$$Y$$$ множество $$$(1,3,2)$$$. Как теперь решить для случая $$$n=3$$$?
Шаг 4Можно например взять ответ из прмеров или например такую строку: "XYZXXZXYYZZY". Как теперь решить задачу для четных $$$n$$$?
Шаг 5Можно разбить числа на пары $$$(1,2),(3,4),\ldots,(n-1,n)$$$, для каждой пары мы можем построить блок длины $$$8$$$, останется их только склеить. А как решить задачу для нечетных $$$n$$$?
Шаг 6Если $$$n$$$ нечетное, то $$$n \ge 3$$$, тогда мы можем построить блок для чисел $$$(n-2,n-1,n)$$$ длины $$$12$$$. Нам остается только решить задачу для оставшихся $$$(n-3)$$$ чисел. А это мы уже умеем делать, т.к. $$$(n-3)$$$ — четное число.
Решение: 377932509
C. Стоимость скобочной последовательности
Шаг 1Первое, на что обратил внимание — это ограничения задачи, которые позволяют ее решить за $$$O(n^2)$$$, то есть можно что-нибудь перебрать за $$$O(n)$$$, а дальше посчитать что-то за $$$O(n)$$$.
Шаг 2У нас есть скобки всего двух типов: "(" и ")". Пусть мы удалим $$$x$$$ скобок "(" и $$$y$$$ скобок ")", тогда $$$x+y \le k$$$. Какие скобки типа "(" нам выгоднее всего удалять?
Шаг 3Нам выгоднее всего удалить $$$x$$$ самых левых скобок "(", почему?
Шаг 4Посмторим на оптимальный ответ. В нем мы можем найти ПСП какой-то длины. Посмотрим на первый символ этой ПСП, он равен "(", причем мы можем считать, что это самая первая скобка в строке (если это не так, тогда мы можем заменить первый символ на скобку "(" левее). Т.к. мы предположили, что мы удалили не $$$x$$$ самых левых скобок "(", тогда есть удаленная скобка, которая правее скобки "(" в ПСП, мы можем вместо удаления этой более правой скобки удалить скобку из ПСП, тогда сама ПСП не увеличится.
Хорошо, а какие тогда скобки ")" нам выгоднее всего удалять?
Шаг 5Нам выгоднее всего удалять $$$y$$$ самых правых скобок ")". Как тогда решать задачу? Что можно перебрать?
Шаг 6Мы можем перебрать $$$x$$$ за $$$O(n)$$$, тогда $$$y=k-x$$$. Остается только удалить скобки за $$$O(n)$$$ и посчитать длину максимальной ПСП в оставшейся строке. Как это сделать?
Шаг 7Можно это сделать жадно. Будем идти слева направо и поддерживать текущее количество скобок "(" без парной ")" (пусть это число равно $$$b$$$), а также количество уже спаренных скобок (это и есть длина ПСП). Если текущий символ "(", что тогда можем сделать?
Шаг 8Можем увеличить $$$b$$$ на единицу, а если текущий символ — это ")"?
Шаг 9Тогда мы можем попытаться спарить эту скобку с какой-то из "(". То есть, если $$$b \gt 0$$$, то мы можем уменьшить $$$b$$$ на единицу и увеличить ответ на $$$2$$$.
Решение: 377946709
D. Товары на полке
Шаг 1Первое, на что обратил внимание, что мы можем сжать координаты и считать, что $$$0 \le a_i \lt n$$$. Тогда для каждого $$$0 \le x \lt n$$$ мы можем выписать все позиции $$$i$$$, что $$$a_i=x$$$.
Шаг 2Как нам для конкретного $$$x$$$ проверить, что все числа в массиве $$$a_i=x$$$ образуют один отрезок?
Шаг 3Пусть $$$l$$$ — минимальная позиция $$$a_l=x$$$, а $$$r$$$ — максимльная, пусть $$$c$$$ — количество элементов в массиве, равных $$$x$$$. Как проверить условие?
Шаг 4Достаточно проверить, что $$$r - l + 1 = c$$$. Хорошо, теперь какой бывает простой случай?
Шаг 5Пусть $$$F(x) = 1$$$, если $$$x$$$ образует единый отрезок и $$$0$$$ иначе. Тогда простой случай, когда $$$F(x)=1$$$ для всех $$$x$$$. Хорошо, осталося случай, когда есть какой-то $$$y$$$, что $$$F(y)=0$$$. Что тогда? Какую позицию тогда точно нужно будет поменять?
Шаг 6Тогда мы знаем, что $$$r-l+1 \gt c$$$ и есть "дырки", то есть позиции, в которых стоят какие-то другие числа. В таком случае мы будем обязаны обменять местами либо $$$l$$$, либо $$$r$$$ с кем-то другим, т.к. иначе величина $$$r-l+1$$$ может только увеличиться, а $$$c$$$ не изменится. Тогда сколько всего можно перебрать пар для обмена местами?
Шаг 7Мы можем перебрать пары $$$(l,i),(r,i)$$$ для всех $$$i$$$, то есть всего есть $$$O(n)$$$ пар. Как нам для конкретной пары проверить, помогает ли она или нет?
Шаг 8Мы можем поддерживать множество позиций в std::set<int>, тогда операцию swap и проверку конкретного $$$x$$$ можно еализовать за $$$O(\log{n})$$$. Как тогда решить задачу?
Шаг 9Давайте поддерживать количество $$$x$$$, что $$$F(x)=0$$$ Давайте переберем все пары для swap , сделаем этот swap и обновим количество плохих $$$x$$$-ов. Если помогло, то выводим ответ, а иначе меняем обратно, возвращая все на место и идем дальше.
Решение: 377946709
E1. Передача перестановки (простая версия)
Шаг 1Зафиксирую конкетную перестановку бит из условия. Какие простые условия можно проверить?
Шаг 2Мы хотим, чтобы не было нуля, а также чтобы все числа были разные. Тогда какое единственное условие может быть нарушено?
Шаг 3Скажем, что перестановка бит хорошая, если максимальный элемент после перестановки бит не больше $$$n$$$. Тогда чему равен ответ?
Шаг 4Он равен количеству хороших перестановок, потому что разные перестановки бит дают разные перестановки массива $$$p$$$. Можем ли мы перебрать все перестановки бит $$$a_0,a_1,\ldots,a_{k-1}$$$?
Шаг 5Да, можем, потому что $$$\log_2(n) \le 11$$$, а $$$11! \le 4\cdot 10^7$$$. Что останется сделать?
Шаг 6Останется проверить, что для конкретной перестановки бит все числа будут не больше $$$n$$$. Что значит, что число $$$x$$$ больше числа $$$n$$$?
Шаг 7Это когда мы сравниваем два числа начиная со старших бит и находим первое несовпадение в бите $$$j$$$ и так оказывается, что $$$n_j=0,x_j=1$$$, то есть $$$j$$$-й бит числа $$$n$$$ равен нулю, а у числа $$$x$$$ он равен единице.
Шаг 8Тогда мы можем перебирать биты начиная со старшего, пусть смотрим на бит $$$j$$$, тогда мы хотим проверить, есть ли число $$$x$$$, что в битах $$$a_q$$$ (здесь $$$q \gt j$$$) в нем стоит то же самое, что в бите $$$q$$$ числа $$$n$$$, а в бите $$$a_q$$$ стоит единица, в то время как у $$$n$$$ стоит ноль. Как мы можем это проверить?
Шаг 9Перебирая биты мы можем поддерживать маску бит, которые нам интересны, а также строить желаемое число которое мы хотим получить. Дальше мы можем запомнить для каждой маски, какие есть числа в исходном массиве, если мы хотим рассматривать только биты из конкретной маски.
Решение: 377975138