Результаты и разбор задач финала Яндекс.Алгоритма 2016

в 14:34, , рубрики: Алгоритмы, Блог компании Яндекс, минск, ненормальное программирование, Программирование, Спортивное программирование, яндекс.алгоритм

29 июля в Минске прошёл финальный раунд чемпионата по программированию Яндекс.Алгоритм. Победителем стал Егор EgorK Куликов — выпускник мехмата МГУ и бывший сотрудник Яндекса. Второе место — у Николы Йокича из Швейцарской высшей технической школы Цюриха. В составе команды школы он был финалистом ACM ICPC. Третье место занял Макото Соэдзима, выпускник Университета Токио. Геннадий Короткевич, победитель двух предыдущих Алгоритмов, занял шестое место.

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

image

В этом году мы получили на четверть больше заявок на участие в Алгоритме, чем год назад, — 4578. Среди участников пока немного девушек — 372. В списке зарегистрировавшихся есть представители 70 стран; больше всего соревнующихся — из России, Индии, Украины, Беларуси, Казахстана, США и Китая. В финале приняли участие 25 человек.

Задачи для Яндекс.Алгоритма составляют сотрудники Яндекса и приглашённые эксперты, среди которых — финалисты и призёры ACM ICPC. По условиям состязания, участники могут использовать разные языки программирования. Статистика Яндекс.Алгоритма показывает, что самый популярный язык — С++; его выбрали более двух тысяч человек. Второе место поделили Python и Java.

Задача A. Место проведения финала

Авторы задачи: Алексей Толстиков, Роман Удовиченко

Имя входного файла: Имя выходного файла: Ограничение по времени: Ограничение по памяти:
стандартный ввод стандартный вывод 3 секунды 512 мегабайт

В этом году финал Яндекс.Алгоритма проходит в Национальной библиотеке Беларуси. Хочется отметить, что здание библиотеки имеет весьма необычную форму — ромбокубоктаэдр.

Ромбокубооктаэдр это полуправильный многогранник, гранями которого являются 18 квадратов и 8 треугольников. Всего у ромбокубооктаэдра 24 вершины и 48 ребер. Изображение ромбокубооктаэдра представлено ниже:

Результаты и разбор задач финала Яндекс.Алгоритма 2016 - 2

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

Так как ответ может достаточно большим, вычислите его по модулю 109 + 7.

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

В единственной строке входных данных записано одно целое число k (1 ⩽ k ⩽ 50), количество цветов в вашем распоряжении.

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

В единственной строке выведите ответ на задачу.

Примеры

стандартный ввод стандартный вывод
1 0
3 356928

Замечание

Одним из вариантов корректной раскраски для k = 3 будет покрасить все треугольные грани в первый цвет (8 граней), все квадратные грани, смежные по ребру с одной из треугольных граней, во второй цвет (12 граней), и все оставшиеся квадратные грани в третий цвет (6 граней).

Разбор задачи A

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

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

Будем сначала красить первую долю, а только потом вторую. Заметим, что при фиксированной раскраске первой доли посчитать количество способов, которыми можно докрасить вторую долю, не составляет труда: каждую вершину второй доли мы красим в отдельности, а значит, общее число способов есть произведение по всем вершинам второй доли v величины k − adj(v), где adj(v) — количество различных цветов среди вершин, смежных v.

Теперь надо каким-то образом перебрать раскраску первой доли. Если явно перебирать цвет для каждой вершины, это потребует порядка 5012 ≈ 2,4 · 1020 операций, что не уложится ни в какие разумные временные рамки. Будем перебирать не сами цвета вершин, а только их разбиение на одинаковые/разные цветовые группы. А именно — для каждой очередной вершины в ходе перебора будем принимать решение, отнести ли её к одному из уже имеющихся цветов вершин, либо завести ли для неё новый. Таких «сжатых» раскрасок уже не так много, всего 4 213 597 штук. Очевидно, информации, содержащейся в сжатой раскраске первой доли, достаточно для того, чтобы понять, сколькими способами можно докрасить вторую долю, надо только не забыть умножить это число на количество способов превратить данную сжатую раскраску в полноценную раскраску (оно равняется A(k, c) = k(k − 1)(k − 2)...(k − c + 1), где c — количество использованных в сжатой раскраске цветов).

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

Альтернативное решение может перебирать раскраску на поясе из 8 средних квадратов, а дальше считать количество способов докрасить одну из половин и возводить его в квадрат, так как верхняя и нижняя половина ромбокубооктаэдра красятся независимо друг от друга.


Задача B. Преобразование последовательности

Авторы задачи: Максим Ахмедов, Глеб Евстропов

Имя входного файла: Имя выходного файла: Ограничение по времени: Ограничение по памяти:
стандартный ввод стандартный вывод 1 секунда 512 мегабайт

Вам дана последовательность a1, a2,..., an, исходно состоящая из n нулей. За один ход вы можете выбрать любой её подотрезок al, al+1,...,ar, а также произвольное целое число x и преобразовать последовательность этот подотрезок, заменив al+k на al+k + (−1)k · x для всех целых 0 ⩽ k ⩽ r − l.

Требуется преобразовать исходную нулевую последовательность в данную последовательность b1, b2,..., bn за минимальное число ходов. Имеется важное ограничение на последовательность bi: гарантируется, что все её элементы принадлежат множеству {−1, 0, 1}.

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

В первой строке входных данных находится единственное целое число n (1 ⩽ n ⩽ 105). Вторая строка содержит n целых чисел b1, b2,..., bn (−1 ⩽ bi ⩽ 1).

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

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

Примеры

стандартный ввод стандартный вывод
2
-1 1
1
5
1 -1 1 1 0
2

Замечание

В первом тесте из условия можно получить требуемую последовательность за один ход, в котором x = −1, l = 1 и r = 2.

Во втором тесте из условия можно действовать следующим образом:
0 0 0 0 0 → 2 -2 2 0 0 → 1 -1 1 1 0

Разбор задачи B

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

Раз мы имеем дело с операциями вида «прибавить на подотрезке одно и то же число», то полезно перейти к последовательности, состоящей из разностей соседних элементов: перейдём от a1, a2,...,an к последовательности b0 = a1, b1 = a2 − a1,..., bi = ai+1 − ai,..., bn = −an. В этой последовательности элементов на один больше, и она удовлетворяет специальному условию, что b0 + b1 +… + bn = 0.

Тогда прибавление константы x на отрезке [l, r] исходной последовательности эквивалентно замене bl−1 → bl−1 + x и br → br − x.

В последовательности ai встречались целые числа от −1 до 1, поэтому в последовательности bi будут встречаться целые числа от −2 до 2. За один ход, как мы уже выяснили, мы можем к одному из чисел прибавить x, а из другого вычесть x, и мы хотим добиться, чтобы в последовательности были одни нули.

Назовём «весом» операции прибавления x и −x к двум элементам последовательности величину |x|.

Докажем вспомогательный факт: если число bi больше (меньше) нуля, то не выгодно применять операции, в которых число bi увеличивается. Формально говоря, если есть оптимальная (т. е. кратчайшая) последовательность операций, в которой какое-то bi в какой-то момент увеличивается, то можно предъявить последовательность операций, в которой ни одно bi никогда не увеличивается, и которая имеет ту же длину.

Действительно, пусть к bi применялись две операции, скажем, 1) bi → bi + x, bj → bj − x и 2) bi + x → bi + x − y, bk → bk +y, и, для определённости, где x,y > 0 и, для определённости, x ⩽ y.

Давайте заменим эти две операции на две других: 1) bi → bi − (y − x) = bi + x − y, bk → bk + y − x и bj → bj − x, bk + y − x → bk + y − x + x = bk + y. Это две эквивалентные операции, они приводят к тем же результатам, но можно увидеть, что суммарный вес двух новых операций уменьшился: |y − x| + |x| = y − x + x = y < x + y = |x| + |y|.

Повторяя такие замены, пока возможно, мы рано или поздно остановимся (потому что суммарный вес операций не может неограниченно убывать, так как он всегда целый и неотрицательный), а значит, можно найти последовательность операций той же длины, в которой любой положительный элемент всегда только уменьшается. Аналогично можно добиться того, что любой положительный элемент будет только увеличиваться.

Это позволяет описать все доступные нам операции. Мы можем либо избавиться от −2 и 2 за один ход, либо избавиться от −1 и 1 за один ход, либо избавиться от −2, 1, 1 за два хода, либо избавиться от 2, −1, −1 за два хода.

Понятно, что суммарный вес всех операций, которые мы произведём, есть сумма всех положительных чисел среди bi (которая противоположна по знаку сумме всех отрицательных чисел). У нас теперь бывают операции веса 1 и веса 2, и понятно, что чтобы минимизировать общее число операций, надо сделать как можно больше операций веса 2. Это приводит нас к жадному алгоритму, а именно — сокращать двойки с минус двойками, пока можем, а когда не больше не можем, сокращать единички и минус единички с чем получится.

Таким образом, ответ это сумма всех положительных bi минус минимум из количества двоек и количества минус двоек.


Задача C. Игра в шляпу

Автор задачи: Глеб Евстропов

Имя входного файла: Имя выходного файла: Ограничение по времени: Ограничение по памяти:
стандартный ввод стандартный вывод 1 секунда 512 мегабайт

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

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

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

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

В первой строке входных данных находится целое число n (1 ⩽ n ⩽ 105), означающее, что за столом сидят 2n человек.

Во второй строке находится последовательность из 2n целых чисел. Каждое целое число от 1 до n встречается в этой последовательности ровно два раза. Эта последовательность описывает разбиение людей, сидящих вокруг стола, на команды, если мы будем их выписывать в порядке обхода по часовой стрелке.

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

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

Примеры

стандартный ввод стандартный вывод
3
2 1 3 2 1 3
0
4
2 1 4 2 3 1 3 4
2

Замечание

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

Во втором тесте из условия один из оптимальных способов будет сначала поменять местами людей, сидящих на первой и седьмой позициях, а потом поменять местами людей, сидящих на седьмой и восьмой позициях, что приведёт нас к корректной рассадке: 3 1 4 2 3 1 4 2.

Разбор задачи C

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

Получившийся граф обладает тем свойством, что в нём из каждой вершины ведёт ровно два ребра (одно — диаметр, а второе — в вершину, в которой сидит человек из той же команды). Такой граф всегда представляет из себя объединение из какого-то количества циклов.

Мы стремимся достигнуть ситуации, когда каждый цикл состоит ровно из двух диаметрально противоположных вершин, то есть когда всего имеется ровно n циклов длины 2.

Поймём, как меняется наш граф под воздействием доступной нам операции. Пусть поменяли местами двух людей не из одной команды (иначе это бессмысленная операция), скажем, человека из вершины a с человеком из вершины b. Пусть партнёр человека a сидит в вершине a′, а партнёр человека b сидит в вершине b′. Тогда из графа пропадут два ребра aa′ и bb′ и образуются два новых ребра ba′ и ab′ (то есть новые рёбра будут идти крест-накрест между концами старых). Легко видеть, что такая операция может либо один цикл разъединить на два, либо не изменить количество циклов, либо склеить два цикла. Значит, ответ никак не меньше, чем n − c, где c — исходное количество циклов. С другой стороны, всегда можно добиться требуемого ровно за столько ходов: достаточно на каждом шаге брать пару сокомандников, которые сидят не друг напротив друга, и просто пересаживать одного из них так, чтобы он сел напротив своего партнёра. Эта операция строго увеличивает количество циклов на один.

Таким образом, ответ есть n − c, где c — количество циклов, или, что то же самое, компонент связности в указанном графе. Эту задачу можно решить и просто явно моделируя процесс рассаживания людей по парам, и это корректно по тем же причинам, которые описаны выше.


Задача D. Кучефицируй меня полностью

Автор задачи: Максим Ахмедов

Имя входного файла: Имя выходного файла: Ограничение по времени: Ограничение по памяти:
стандартный ввод стандартный вывод 2 секунды 512 мегабайт

Вы — простой паренёк, который хочет лишь одного: чтобы ему на день рождения подарили двоичную максимальную кучу, потому что у всех ваших друзей уже такая есть! Наконец, вы пошли с родителями в магазин, но, к сожалению, там закончились все двоичные кучи, и всё, что осталось — это старое полное двоичное дерево. Оно состоит из n = 2h − 1 вершин, в которых записаны некоторые значения, не обязательно удовлетворяющие главному свойству максимальной кучи. К счастью, Старый Джо согласился помочь вам превратить это дерево в двоичную кучу за определённую плату.

Полное двоичное дерево высоты h это корневое дерево, состоящее из n = 2h − 1 вершин, пронумерованных от 1 до n, такое, что для любого 1 ⩽ v ⩽ 2h-1 − 1 вершина v является предком для вершин 2v и 2v + 1.

Двоичная максимальная куча высоты h это полное бинарное дерево высоты h, у которого в вершинах находятся значения h1, h2,..., hn, при этом значение в любой вершине не меньше, чем значение в её детях (если у неё есть дети).

Вам дано полное бинарное дерево высоты h, в вершинах которого находятся значения a1,a2,...,an. Также, с каждой вершиной связана стоимость cv, означающая, что Старый Джо может как увеличить, так и уменьшить значение в вершине v на произвольную величину x > 0 за стоимость в cvx. Вы можете менять значения в произвольном количестве вершин.

Определите минимальную стоимость преобразования данного полного бинарного дерева в максимальную кучу.

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

В первой строке ввода находится единственное целое число n (1 ⩽ n ⩽ 218−1), количество вершин в полном бинарном дереве, которое вам досталось. Гарантируется, что n = 2h − 1 для некоторого целого h.

Во второй строке ввода находятся n целых чисел a1, a2,..., an (0 ⩽ ai ⩽ 106), текущие значения вершин дерева.

В третьей строке находятся n целых чисел c1, c2,..., cn (0 ⩽ ci ⩽ 106), стоимости изменения значений в вершинах дерева.

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

Выведите минимальную стоимость преобразования данного полного бинарного дерева в максимальную кучу.

Пример

стандартный ввод стандартный вывод
7
4 5 3 1 2 6 6
4 7 8 0 10 2 3
19

Замечание

В тесте из условия оптимальным способом будет увеличить значение в вершине 1 на 2 ценой в 4 · 2 = 8 и уменьшить значения в вершинах 6 и 7 на 3 ценой в 2 · 3 = 6 и 3 · 3 = 9 соответственно. Таким образом, общая стоимость будет равна 8 + 6 + 9 = 23.

Разбор задачи D

Введём обозначения. Пусть Lv(x) — это минимальная цена, которую надо заплатить, чтобы поддерево вершины v стало корректной кучей, а в самой вершине v стояло число, не превосходящее x. Пусть Sv(x) — это величина, которая определяется абсолютно аналогично, только в самой вершине v должно стоять строго число x. Тогда ответ на задачу равняется значению минимума функции Sv(x).

Для листовых вершин v по условию имеем, что Sv(x) = cv|x − av|. Аналогично можно понять, что Lv(x) = max{0, cv(av − x)}.

Выразим Sv(x) через L2v(x) и L2v+1(x) (то есть функцию S вершины v через функции L её детей). Верно следующее соотношение:

Sv(x) = cv|x − av| + L2v(x) + L2v+1(x).

Действительно, если в вершину v мы ставим значение x, то мы платим, во-первых, за изменение самой вершины v, и во-вторых, мы должны поменять поддеревья v каким-то образом, чтобы значение в v оказалось не меньше значений в её детях, а эту стоимость мы можем получить из функции L для детей.

Lv(x) мы сейчас научимся считать по Sv(x). Но давайте в этом месте остановимся и выскажем предположение, какой вид имеют функции Lv и Sv. Можно догадаться, что они будут кусочно-линейными функциями переменной x, но на самом деле верно даже более сильное условие: они будут выпуклыми кусочно-линейными функциями (другими словами, угол наклона каждого следующего звена возрастает). Давайте строго это докажем: пусть это верно для вершин 2v и 2v + 1. Тогда Sv(x), как следует из формулы выше, тоже выпуклая кусочно-линейная функция (так как является суммой трёх выпуклых кусочно-линейных функций).

Теперь уже Lv(x) легко получить по Sv(x): рассмотрим точку глобального минимума Sv(x). До этой точки Sv(x) убывает, а после неё возрастает. Для того, чтобы получить Lv(x), надо просто заменить участок возрастания Sv(x) на константный горизонтальный участок со значением, равным глобальному минимуму функции Sv(x).

Заметим, что для того, чтобы задать функции Lv и Sv, нужно O(size(v)) информации о точках излома этих функций, где size(v) — это размер поддерева вершины v. Действительно, точек излома в графике функции Sv(x) не больше, чем суммарно точек излома в графиках функций S2v и S2v+1 плюс ещё одна точка излома из-за слагаемого cv|x − av|. Получается рекуррента T(v) = T(2v) + T(2v + 1) + 1 на количество хранимой в худшем случае информации, решением которой является T(v) = size(v).

Непосредственно реализовать основную формулу, используемую в задаче, можно за линейную сложность от размеров сливаемых функций. Таким образом получается решение за Результаты и разбор задач финала Яндекс.Алгоритма 2016 - 3 size(v) = nk = n · log2 n.


Задача E. Отделяй и властвуй

Автор задачи: Михаил Тихомиров

Имя входного файла: Имя выходного файла: Ограничение по времени: Ограничение по памяти:
стандартный ввод стандартный вывод 5 секунд 512 мегабайт

Последовательность чисел называется хорошей, если ее можно построить согласно следующим правилам:

  • пустая последовательность является хорошей;
  • если X и Y — хорошие последовательности, то XY (конкатенация X и Y) также является
    хорошей;
  • если X — хорошая последовательность, а n — любое число, то nXn (число n, потом все элементы X, и, наконец, опять число n) также является хорошей последовательностью.

Например, последовательность (1, 2, 2, 1, 3, 3) является хорошей, а последовательность (1, 2, 1, 2) — нет.

Последовательность называется разделимой, если существует способ разбить ее на две хорошие подпоследовательности (любая из них может быть пустой). Например, последовательность (1, 2, 1, 2) является разделимой (поскольку ее можно разбить на хорошие подпоследовательности (1, 1) и (2, 2)), а последовательность (1, 2, 3, 1, 2, 3) — нет.

Рассмотрим все последовательности из 2n чисел, такие что каждое число от 1 до n встречается ровно дважды. Сколько из них являются разделимыми? Найдите ответ по модулю 109 + 7.

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

В единственной строке ввода записано одно целое число n (1 ⩽ n ⩽ 500).

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

Выведите одно целое число — ответ на задачу по модулю 109 + 7.

Примеры

стандартный ввод стандартный вывод
1 1
2 6
4 2016

Разбор задачи E

Как проверить, является ли последовательность отделимой? Для данной последовательности построим граф на n вершинах. Вершины i и j соединим ребром, если пары соответствующих чисел нельзя включить в одну ПСП (т. е., например, когда числа расположены как (i, j, i, j) либо (j, i, j, i), но не (i, i, j, j) или (i, j, j, i)). Последовательность отделима тогда и только тогда, когда получившийся граф двудолен.

Обозначим за f(n) количество отделимой последовательностей из n пар чисел, при этом последовательности, отличающиеся перенумеровкой чисел, мы будем считать одинаковыми. Введем вспомогательную функцию g(n) — количество примитивных последовательностей, т. е. отделимой последовательностей из n пар чисел, для которых существуют ровно один способ разделения на две ПСП (это в точности те же последовательности, для которых граф, описанный выше, связен).

Пусть мы знаем значения g(n), вычислим теперь f(n). Для произвольной отделимой последовательности рассмотрим компоненту связности, содержащую первое число. Пусть она содержит k пар чисел, тогда между ее элементами есть 2k промежутков, в каждый из которых можно поставить любую отделимой последовательность независимо друг от друга. Обозначим F (n, k) количество способов выбрать k отделимых последовательностей суммарной длины 2n. Тогда из рассуждений выше получаем f(n) = Результаты и разбор задач финала Яндекс.Алгоритма 2016 - 4 g(k) F(n − k, 2k). Величины F(n, k) тривиально пересчитываются друг через друга и очередные значения f(n).

Как найти g(n)? Назовем конфигурацией спобов разбить 2n элементов на два множества и построить ПСП на каждом из них независимо. Количество конфигураций на 2n элементах t(n) вычисляется тривиально. Вычтем из этого количества все конфигурации, не относящиеся к примитивным последовательностям, оставшееся количество будет равно 2g(n). Снова рассмотрим компоненту связности, содержащую первое число, пусть в ней k пар чисел. Количество таких конфигураций равно 2g(k) T(n − k, 2k), где T (n, k) — количество способов выбрать k конфигураций с суммарным количеством элементов 2n. Таким образом, g(n) = Результаты и разбор задач финала Яндекс.Алгоритма 2016 - 5 (T(n) − Результаты и разбор задач финала Яндекс.Алгоритма 2016 - 6 g(k) T(n − k, 2k). Величины T(n, k) вычисляются тривиально через t(n), которые находятся явно. Суммарная сложность этого решения O(n3).


Задача F. Дроби

Автор задачи: Олег Христенко

Имя входного файла: Имя выходного файла: Ограничение по времени: Ограничение по памяти:
стандартный ввод стандартный вывод 2 секунды 512 мегабайт

Задана последовательность a1, a2,..., an, элементы ai которой являются дробями, записанными в виде p/q, где p — целое, а q — целое положительное (при этом их взаимная простота не гарантируется).
Проверьте, что для каждой пары i,j (1 ⩽ i < j ⩽ n) существует как минимум одно 1 ⩽ k ⩽ n такое, что ai · aj =ak.

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

Первая строка входных данных содержит одно целое число n (1 ⩽ n ⩽ 3 · 105) — длину последовательности. В следующей строке записаны n дробей в формате p/q (p и q целые, |p| ⩽ 109, 1 ⩽ q ⩽ 109).

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

Выведите «Yes», если для каждой пары различных i и j найдётся требуемое k, и «No» в противном случае.

Примеры

стандартный ввод стандартный вывод
1
7/42
Yes
3
3/3 0/1 -5/5
Yes
2
2/1 3/2
No

Разбор задачи F

Сократим все дроби. Произведём несколько наблюдений.

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

Во-вторых, заметим, что в каждом из множеств 0 < |x| < 1 и 1 < |x| есть не более одно го числа. Действительно, если, например, на 0 < |x| < 1 есть больше одного числа, то выберем из всех представленных там чисел два минимальных по абсолютному значению (скажем, a и b), возьмём их произведение ab, и оно будет иметь ещё меньшее ненулевое абсолютное значение: 0 < |ab| = |a||b| < min{|a|, |b|}, а значит, оно не совпадает ни с одним из чисел в нашем множестве. Аналогично с диапазоном 1 < |x|.

Таким образом, после сокращения и удаления дубликатов при условии, что ответ — Yes, в нашем множестве может быть не более восьми чисел: два нуля, две единицы, две минус единицы и по одному числу из указанных диапазонов. Значит, можно придерживаться следующей логики: сократим все числа, оставим от каждого числа не более двух его копий. Если получилось больше восьми чисел, то ответ однозначно No, иначе можно рассмотреть все пары чисел, благо их совсем немного, и честно проверить требуемое условие.

Автор: Яндекс

Источник

Поделиться новостью

* - обязательные к заполнению поля