Pull to refresh
510.11
Яндекс
Как мы делаем Яндекс

Яндекс.Алгоритм 2018: оптимизационный трек и ML-задача от разработчиков Алисы

Reading time 12 min
Views 21K

Сегодня мы открываем регистрацию на международный конкурс по программированию Яндекс.Алгоритм. В этом году мы решили не только запуститься раньше, но и добавили два новых трека: оптимизационный и трек по машинному обучению. Каждый участник может выбрать, в каких треках участвовать.




А теперь по порядку. Открывает соревнование этого года алгоритмический трек. Он пройдет в классическом варианте с правилами tcm/time и системой «гран-при 30». Квалификационный раунд стартует уже 17 февраля. Каждый, кто решит минимум одну задачу, пройдет в отборочный тур и сможет побороться за стильные футболки, которые достанутся ТОП-256 и денежные призы для трех победителей трека. Ссылка на регистрацию.

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


Разбор задач

A. Время в зазеркалье


Ограничение времени 1 секунда
Ограничение памяти 512Mb


В офисе, где работает Бомбослав, установлены стильные дизайнерские часы. Их циферблат имеет стандартную разметку: на окружности расположены 60 делений, соответствующих минутам, 12 из которых (начиная с расположенного вверх от центра окружности, далее равномерно с шагом в пять делений) сделаны крупнее остальных, то есть соответствуют часам. Стильными эти часы делает тот факт, что циферблат не содержит никаких цифр, так как предполагается, что всем хорошо известно, какое деление соответствует какому значению текущего времени.


Сегодня над рабочим местом Бомбослава повесили такие часы. Периодически поглядывая на них, он сначала заметил некоторую странность в направлении движения стрелок. Приглядевшись внимательнее, Бомбослав обнаружил, что на самом деле над его рабочим местом находится зеркало, а часы расположены на стене за его спиной. Это означает, что Бомбослав видит циферблат отражённым относительно вертикальной оси, проходящей через его центр. Теперь он хочет научиться быстро определять настоящее текущее время, зная время, которое показывается на отражённом циферблате.


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


Формат ввода
В единственной строке входных данных записаны два целых числа $h$ и $m$ ($0 \le h \le 11$, $0 \le m \le 59$) — положение часовой стрелки и положение минутной стрелки в отражённом циферблате соответственно. $h=0$ означает, что часовая стрелка указывает вертикально вверх, $h=3$ соответствуют стрелке, направленной строго направо, $h=6$ — стрелка смотрит вертикально вниз, $h=9$ — строго налево. Аналогичные указания верны для минутной стрелки для значений $m=0, m=15, m=30$ и $m=45$.


Формат вывода
Выведите два целых числа $x$ и $y$ ($0 \le x \le 11$, $0 \le y \le 59$) — реальное значение текущего времени на часах.




Решение:
Рассмотрим движение "прямой" и "отражённой" стрелки. За то время, когда "прямая" стрелка повернётся на некоторый угол, "отражённая" повернётся на тот же угол, но в другую сторону, то есть суммарный угол поворота стрелок равен полному обороту. Для каждой стрелки независимо вычислим её позицию. Для часовой это 12 минус текущая позиция, а для минутной — 60 минус текущая позиция. В обоих случая надо не забыть заменить 12 или 60 на ноль.


B. Фактор палиндромности


Ограничение времени 1 секунда
Ограничение памяти 512Mb


Аркадий — большой фанат использования машинного обучения в любой задаче. Он верит в безграничную силу волшебства этой популярной молодой науки. Именно поэтому Аркадий постоянно постоянно придумывает всё новые и новые факторы, которые можно вычислить для различных объектов.


Напомним, палиндромом называется строка, которая одинаково читается от начала к концу и от конца к началу. Для каждой строки в своей базе данных Аркадий хочет найти самую короткую её подстроку, состоящую хотя бы из двух символов и являющуюся палиндромом. Если таких подстрок несколько, Аркадий хочет выбрать лексикографически минимальную.


Формат ввода
В единственной строке входных данных записана одна строка из базы Аркадия — непустая последовательность строчных букв английского алфавита. Длина строки составляет не менее 2 и не превосходит 200000 символов.


Формат вывода
Выведите минимальную по длине подстроку строки из входных данных, состоящую хотя бы из двух символов и являющуюся палиндромом. Напомним, что среди всех таких строк Аркадий хочет найти лексикографически минимальную.




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


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


C. Разделите их все


Ограничение времени 1 секунда
Ограничение памяти 512Mb


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


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


Когда Оля и Толя наконец закончили прорабатывать все условия разделения мишеней на две части, они начали сомневаться, что провести такую прямую вообще возможно, и просят вас ответить на этот вопрос.


Формат ввода
В первой строке входных данных записано целое число $n$ ($1 \le n \le 100000$) — количество мишеней. Каждая из последующих $n$ строк содержит целое число $t_i$ ($0 \le t_i \le 1$), обозначающее тип мишени. Если $t_i=0$, то мишень является кругом и далее следуют три целых числа $r_i$, $x_i$ и $y_i$, определяющие радиус и координаты центра круга соответственно ($1 \le r_i \le 1000$, $−10000 \le x_i, y_i \le 10000$). Если же $t_i=1$, то мишень является прямоугольником, который затем определяют восемь целых чисел $x_{1,i}, y_{1,i}, x_{2,i}, y_{2,i}, x_{3,i}, y_{3,i}, x_{4,i}, y_{4,i}$ — координаты всех четырёх вершин ($−10000 \le x_{j,i},y_{j,i} \le 10000$), перечисленных в порядке обхода по часовой стрелки или против часовой стрелки. Гарантируется, что данные четыре вершины образуют прямоугольник ненулевой площади.


Формат вывода
Если существует прямая, которая поделит каждый из имеющихся кругов и прямоугольников на две части одинаковой площади, выведите “Yes”. В противном случае выведите “No”.




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


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


Если среди построенного множества точек не более двух различных, то ответ точно положительный. В противном случае рассмотрим любую пару различных точек, и проверим, что все остальные точки лежат на определяемой этой парой прямой. Наиболее удобный способ проверить, что три точки $a$, $b$ и $c$ ($a \ne b$) лежат на одной прямой — использовать векторное произведение векторов $b - a$ и $c - a$. Итоговая сложность решения: $O(n)$.


D. Задача для собеседования


Ограничение времени 3 секунды
Ограничение памяти 512Mb


Алексей регулярно проводит собеседования с кандидатами на позицию стажёра. И хотя он провёл уже не одну сотню собеседований, в последнее время этот процесс даётся ему нелегко — кандидаты стали без труда решать все годами протестированные и отработанные задачи Алексея!


Делать нечего, и в преддверии очередного собеседования Алексей придумал новую задачу. Имеется числовая последовательность, на первом шаге состоящая из двух чисел 1. На каждом шаге следующем шаге между каждыми двумя соседними элементами добавляется новый элемент, равный их сумме. После первых нескольких шагов последовательность выглядит следующим образом:
1 1
1 2 1
1 3 2 3 1
1 4 3 5 2 5 3 4 1


На собеседовании Алексей хочет попросить кандидата написать программу, которая по заданному числу $n$ будет определять, сколько раз число $n$ будет встречаться в последовательности на $n$-м шаге? Алексей ещё не научился решать свою задачу, но слышал, что кандидат, которого он будет сейчас собеседовать, добился высоких результатов в спортивном программировании, поэтому, скорее всего, легко справится с этим вопросом.


Формат ввода
Во входных данных записано единственное число $n$ ($1 \le n \le 10^{13}$).


Формат вывода
Выведите одно целое число, равное количеству вхождений числа $n$ в описанную в условию последовательность на шаге $n$.




Решение:
Докажем несколько лемм.


Лемма 1. Числа, оказавшиеся на каком-то шаге соседними, являются взаимно простыми.


Докажем по индукции. База очевидна (1 и 1 взаимно просты). Пусть доказано для $n$ шагов. Все числа, выписанные на $n+1$-м шаге, являются суммой
двух соседних на $n$-м шаге чисел, то есть суммой двух взаимно простых чисел. Но НОД ($a+b$, $b$) = НОД ($a$,$b$)=1. Лемма доказана.


Лемма 2. Никакая упорядоченная пара соседних чисел $(a,b)$ не может возникнуть в последовательности более одного раза (ни на одном шаге, ни на разных).


Пусть это не так, тогда отметим номер $k$ шага, на котором в первый раз возникло повторение (то есть повторилась пара, существующая на этом или на предыдущем шаге). Пусть пара $(p,q)$ возникла на $k$-м и на $i$-м шаге ($i \le k$). Но тогда, если $p>q$, то $p$ было построено как сумма соседей $q$ и $p-q$ (если $p<q$, то $q$ было построено как сумма $p$ и $q-p$), то есть на $k-1$-м и на $i-1$-м шагах также существовало повторение, что противоречит нашему предположению.
Лемма доказана.


Лемма 3. Любая упорядоченная пара взаимно простых чисел неизбежно будет соседней на некотором шаге.


Пусть мы имеем числа $pq$, стоящие рядом на некотором шаге и пусть $p>q$ (без ограничения общности). Тогда $p$ было получено как сумма $p-q$+$q$, то есть на предыдущем
шаге рядом стояли $p-q$ и $q$. Если $p-q < q$, то два шага назад справа от $q$ стояло число $2q-p$, если $p-q > q$, то слева от $p-q$ стояло число $p-2q$ и так далее. Так как $p$ и $q$
взаимно просты, то на каком-то шаге этот процесс, по сути являющийся разновидностью алгоритма Евклида, приведёт к тому, что с одной стороны окажется $1$, а с другой — некоторое
натуральное число. Но пара $(1,x)$ или $(x,1)$ для любого $x$ будет соседней последовательности на $x$-м шаге. А так как действия восстанавливаются однозначно,
то это значит, что и исходная пара $(p,q)$ в какой-то момент встретится в качестве соседней.


Таким образом, каждая упорядоченная пара взаимно простых чисел ровно один раз встречается в качестве соседей в заданной последовательности. Поэтому задача сводится к подсчёту количества упорядоченных пар взаимно простых чисел, дающих в сумме $n$. Так как если $p$ и $n$ взаимно просты, то и $p$ и $n-p$ взаимно просты, то количество таких пар можно поставить в однозначное соответствие количеству чисел, взаимно простых с $n$, или значению функции Эйлера от $n$.


Подсчёт же количества таких чисел является известной задачей и опирается на мультипликативность функции Эйлера: если $n=p_1^{k_1} \cdot p_2^{k_2} \cdot \ldots \cdot p_n^{k_n}$, то взаимно простых с $n$
чисел будет $(p_1^{k_1}-p_1^{k_1-1}) \cdot (p_2^{k_2}-p_2^{k_2-1}) \cdot \ldots (p_n^{k_n}-p_n^{k_n-1})$. Раскладываем $n$ на простые множители за время $O(\sqrt{n})$.


E. Резервное копирование


Ограничение времени 5 секунд
Ограничение памяти 512Mb


Для обеспечения сохранности пользовательских данных Аркадий постоянно изобретает и тестирует новые схемы организации резервного копирования. В этот раз он пронумеровал все имеющиеся у него компьютеры с данными от 1 до $n$ и для каждого компьютера с номером от 1 до $n−1$ назначил резервный компьютер $p_i$. При этом он строго соблюдал правило, что номер компьютера для резервного копирования всегда больше номера самого компьютера, то есть $p_i>i$. По этой причине, у компьютера с номером $n$ компьютера для резервного копирования нет.


В ходе текущего эксперимента Аркадий выбрал некоторую конфигурацию значений $p_i$ и будет последовательно отключать компьютеры по одному каждую секунду. Эксперимент заканчивается, когда Аркадий отключает компьютер с номером $n$. Изначально, на каждом компьютере находится некоторый блок данных размера 1. При отключении компьютера с номером $x$, изначально расположенный на нём блок данных размера 1 передаётся на компьютер с номером $p_x$, при этом, если на компьютере номер $x$ находилось другие блоки данных (полученные от других компьютеров при их отключении), то они исчезают. Если же компьютер $p_x$ уже отключен, то и блок данных с компьютера $x$ никуда не передаётся и тоже исчезает.


Аркадий хочет, чтобы эксперимент продолжался как можно дольше, но он вынужден соблюдать ещё одно дополнительное ограничение: если на каком-либо компьютере собирается $k$ блоков данных, то в целях сохранности железа этот компьютер необходимо тут же выключить в течение следующей секунды. Обратите внимание, что последняя секунда (во время которой выключается компьютер $n$) не учитывается.


Формат ввода
В первой строке входных данных записано целое число $t$ ($1 \le t \le20$) — количество тестовых примеров.


Далее следует $t$ описаний тестовых примеров, каждое описание начинается со строки содержащей два целых числа $n$ и $k$ ($1 \le n \le 100000$, $2 \le k \le 10$) — количество компьютеров, участвующих в эксперименте и предельное количество блоков данных на одном компьютере соответственно. Вторая строка содержит $n−1$ число $p_1, p_2 , \ldots, p_{n−1}$ ($i+1 \le p_i \le n$).


Формат вывода
Для каждого из $t$ тестовых примеров выведите одно целое число — максимально возможную продолжительность эксперимента, то есть максимальный номер секунды, на которой Аркадий может отключить компьютер с номером $n$.




Решение:
В задаче нам дано корневое дерево, на каждом шагу одна из вершин дерева удаляется. При этом, если корень вершины ещё не был удалён, то его значение увеличивается на 1 (изначально все значения равны 1). Если значение какой-то вершины становится равным $k$, то именно она удаляется на следующем шаге. Требуется максимизировать номер шага на котором будет удалена корневая вершина.


Заметим, что если у корневой вершины менее $k - 1$ потомка, то можно удалить все вершины дерева, перед тем как трогать вершину номер $n$. В противном случае, все дети корня разделяются на три множества: те, чьи поддеревья будут удалены полностью, те, у которых корень останется не тронутым, и одно поддерево, после удаления корня которого мы удаляем и саму вершину $n$. Сделаем обход в глубину нашего дерева и будем поддерживать три значения динамического программирования:


$a(v)$ равняется количеству вершин, которые можно удалить в данном поддереве, если можно удалить вершину $v$ и не обязательно последней. Несложно заметить, что $a(v)$ равняется размеру поддерева.


$b(v)$ равняется количеству вершин, которые можно удалить в данном поддереве, если вершина $v$ должна остаться не тронутой. Равняется $a(v) - 1$, если у вершины $v$ менее $k - 1$ сына. В противном случае нужно выбрать каких-то $k - 2$ потомка, для которых будет использовано значение $a(u)$ и для всех остальных использовать $b(u)$. В качестве таких $k - 2$ потомков выгодно взять вершины с максимальной разницей $a(u) - b(u)$.


$c(v)$ равняется количеству вершин, которые можно удалить в данном поддереве, если можно удалить вершину $v$, но она должна быть последней удалённой вершиной поддерева. Величина $c(n)$ и будет являться ответом на задачу. Требуется выбрать какие-то $k - 2$ потомка, для которых будет использовано значение $a(u)$, одного потомка, для которого мы используем $c(u)$ и для всех остальных к ответу добавится $b(u)$. Переберём, для какого из потомков будет использовано $c(u)$ (то есть кто будет последним удалённым потомком, после чего будет удалена и вершина $v$). Теперь среди оставшихся требуется взять сумму всех значение $b(u)$ и $k - 2$ максимальных $a(u) - b(u)$. Для этого достаточно иметь предподсчитанными сумму всех $b(u)$ и список сыновей, упорядоченных по $a(u) - b(u)$. Если вершина $x$, для которой мы решили взять значение $c(x)$ попадает в вершины с максимальной разностью, то использовать следующую $k - 1$ вершину (такая обязательно есть, иначе мы просто уничтожаем всё поддерево).


Итоговая сложность решения $O(n \log n)$.


F. Процессоры-лжецы


Ограничение времени 3 секунды
Ограничение памяти 512Mb


Для испытания новых алгоритмов машинного обучения Евгений использует $n \cdot m$ процессоров, расположенных в единичных клетках платы размера $n \times m$. Таким образом, процессоры занимают $n$ рядов, по $m$ процессоров в каждом. При этом два процессора считаются соседними, если они расположены в соседних клетках одного ряда, или на одной и той же позиции в соседних рядах.


В результате неудачного эксперимента с новым алгоритмом некоторые из процессоров научились врать Евгению. Однако, благодаря тому, что была использована только базовая версия алгоритма, если какой-то процессор начинает врать, то он будет делать это всегда, поэтому результаты его работы всё ещё не сложно интерпретировать.


Теперь перед Евгением стоит задача определить, какие из процессоров постоянно выдают неверную информацию, но сначала он хочет оценить масштаб проблемы. Для этого он послал каждому из процессоров вопрос: верно ли, что среди соседних ему процессоров есть и исправные процессоры, и процессоры-лжецы? На удивление Евгения, все процессоры ответили на такой запрос утвердительно. Теперь он хочет узнать, какое минимальное количество процессоров-лжецов может находится на плате?


Формат ввода
В единственной строке входных данных записаны два целых числа $n$ и $m$ ($1 \le n \le 7$, $1 \le m \le 100$) — количество рядов в плате и количество процессоров в одном ряду соответственно.


Формат вывода
Выведите одно целое число — минимальное возможное количество процессоров-лжецов на плате, при котором каждый процессор мог сообщить Евгению, что среди его соседей есть и исправные процессоры и процессоры-лжецы.




Решение:
Воспользуемся тем фактом, что $n \le 7$ и будем вычислять динамику по профилю. Пусть мы заполнили первых $i$ столбцов таблицы, причём на первых $i - 1$ столбце все процессоры вернули ожидаемый результат. Тогда, для того чтобы продолжить заполнять таблицу нам важно лишь знать, какие из процессоров врут среди последних двух столбцов.


Посчитаем $dp(i, m_1, m_2)$, где $i$ меняется от 1 до $m$, а $m_1$ и $m_2$ — битовые маски от 0 до $2^n - 1$. Значением динамики будет минимальное количество процессоров-лжецов, которое потребуется, чтобы заполнить первые $i$ столбцов так, чтобы среди первых $i - 1$ столбца все процессоры вернули ожидаемый результат, а состояние процессоров в последнем и предпоследнем столбце были равны $m_1$ и $m_2$ соответственно. Всего различных состояний $O(m \cdot 2^{2n})$. Наконец, для вычисления перехода будет перебирать новую маску $m_3$ и пробовать перейти в состояние $dp(i + 1, m_2, m_3)$.


Работая с масками с помощью предподсчёта и битовых операций получим результат $O(m \cdot 2^{3n})$. Работу программы можно значительно ускорить, если предпосчитать все корректные переходы их каждой пары масок $(m_1, m_2)$ (то есть запомнить все подходящие к ним маски $m_3$).


Упражнение: придумайте, как получить решение за время $O(nm 2^{2n})$.


Дальше — уже знакомый по прошлому году оптимизационный трек. В этом году он будет состоять из двух раундов, по одной задаче в каждом. Задачи подготовят команды Поиска и Беспилотников Яндекса. На решение каждой задачи у участников будет неделя. Три победителя определятся по результатам обоих раундов и получат денежные призы. ТОП-128 участников трека получат футболки с символикой конкурса.


Последним стартует новый и самый продолжительный — трек по машинному обучению. Он будет состоять из одной задачи, подготовленной для участников командой разработки голосового помощника Алиса и продлится целый месяц. Задача обещает быть интересной и дать возможность применить для ее решения весь ассортимент методов машинного обучения. По результатам будут определены три победителя, которые получат денежные призы. ТОП-128 участников трека получат футболки с символикой конкурса.


Победителей всех треков мы будем рады видеть на финале Яндекс.Алгоритма в Санкт-Петербурге и обещаем для них интересную программу.


А какие соревнования по программированию нравятся вам?

Tags:
Hubs:
+37
Comments 16
Comments Comments 16

Articles

Information

Website
www.ya.ru
Registered
Founded
Employees
over 10,000 employees
Location
Россия
Representative