Блог пользователя yeputons

Автор yeputons, 13 лет назад, По-русски

Так как остальные задачи я не то что не пытался решить, а даже не читал, публикую те решения, которые узнал

Задача A. Домино

Для начала поймём, что на квадраты 2x2 всё поле разбивается однозначно и это можно сделать жадным алгоритмом. Теперь у нас есть 14 квадратов. Далее можно сделать необязательное преобразование, от которого лично мне стало жить проще: построим граф на 14 вершинах, ребро между вершинами будет тогда и только тогда, когда у соответствующих квадратов есть общая доминошка. В принципе, это даже какой-то оптимайз по времени, но не суть важно.
Теперь задача такова: есть граф на 14 вершинах, надо раскрасить их в цвета от 0 до 6 так, чтобы все рёбра были разными (два ребра одинаковы, если цвета концов совпадают). Утверждается, что решение - перебор. Перебираем цвет первой, второй, третьей, ..., 14й вершины, на каждом шаге проверяем, что у нас не появилось ребро той же расцветки, что уже было (естесственно, делаем это массивом bool'ов). После чего останется вывести ответ и какую-нибудь раскраску.
Однако это решение может не зайти по времени. Остался один мощный оптимайз. Заметим, что, по сути, разницы между цветами нет. Значит, цвета в раскраске можно переставлять как угодно. Теперь научимся считать количество ответов с точностью до перестановок цветов, а в конце домножим его на 7!=5040. Это просто: достаточно ввести условие, что цвет очередной вершины либо встречался раньше, либо идет сразу после максимального использованного цвета. Например, после цветов 0 1 2 1 0 2 могут идти только цвета 0..3.
Чтобы уверовать в то, что это решение зайдёт, можно грубо оценить количество ответов. Каждая вершина раскрашена в один из семи цветов, каждый цвет встречается ровно два раза, плюс мы не учитываем различные перестановки. Итого получается , что, очевидно даже при отсечении на последнем шаге рекурсии, влезает в TL.

Задача B. Надмножество

Задача была немножко (или множко?) идейной. Одним из возможных решений является разделить множество точек пополам веритикальной прямой (если не получается ровно, та так, чтобы разница была минимальна), решить задачу рекурсивно для двух половин, и добавить на разделяющую прямую точки со всеми встречающимися в ответах для половин y'ами.
Докажем корректность. Если точки лежат в одной половине, всё мы верим, что верно решили подзадачу. Если же они лежат в разных половинах, то их bounding box пересекает нашу прямую, и в точках пересечения выделенные точки есть (посльку их y'и встречались слева и справа).

Прошу сообщество рассказать остальные задачи в комментариях
  • Проголосовать: нравится
  • +15
  • Проголосовать: не нравится

13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
А как в B может не получиться разделить? Нам же абсолютно не важно, есть ли точки в левом и правом множестве с одинаковыми абсциссами. А иначе на тесте где все точки на 1 вертикальной прямой их больше никак разделить не выйдет.
  • 13 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится +3 Проголосовать: не нравится

    Делиться надо пополам, чтобы при спуске в рекурсию не получился квадрат по времени.
    А не получиться ровно пополам может очень просто: точек нечётно :)
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Ну то что пополам это понятно. Я просто думал что ты предлагаешь делить не по количеству, а по иксу и из-за этого может не получиться. 
      А насчет нечетного количества - да, не подумал :)
13 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

Для С наметки, могу жестоко гнать.

Пусть a[i] - частота появления i участников
Тогда (\sum это сумма по всем i)
\sum a[i]*p[i] => max
\sum a[i]*i <= n/2
\sum a[i] = 1

любое a[i] >= 0

Это задача линейного программирования с двумя ограничениями, и, если я ничего не путаю, то в ее решении не более 2 отличных от нуля переменных. Можно их перебрать и свести задачу к наилучшей из
x*p[i] + y*p[j] => max
x*i + y*j <= n/2
x+y = 1
x,y >= 0
и дальше решить это, разобрав 2 случая
  • 13 лет назад, # ^ |
      Проголосовать: нравится +11 Проголосовать: не нравится
    Задача C "Выигрышная стратегия"
    Как я понял, участники из верхней части таблицы сдали в задаче C бипоиск по ответу, внутри которого не самая тривиальная проверка. Мое решение достаточно простое, но отработало за 1.3 сек:
    Любое состояние можно задать одним числом - количеством однократных финалистов, ведь тех, кто еще ни разу не был на финале у нас бесконечно много в любой момент времени, а двухкратные финалисты нам вообще уже не интересны.
    Очевидно, что мы можем начать с какого-то момента, а потом, достигнув определенного количества однократных финалистов равного K, мы будем повторять определенную последовательность действий и снова получать K. Таким образом, мы будем бесконечно повторять эту последовательность и она и определит среднее количество побед - то есть величину, которую нам требуется найти.
    Очевидно, что существует такое K, не превышающее N.
    Никогда нет смысла набирать более, чем 2N однократных финалистов. Ведь если у нас есть 2N однократных финалиста, то мы можем использовать хоть N из них, а на следующем ходу, у нас все равно будет тот же набор вариантов действий.
    Несложно заметить, что длина периода всегда будет не более 2N действий, это следует из того, что состояний различных внутри периода будет не больше, чем уникальных состояний (а их всего-то 2N + 1).
    Ну и теперь остается только перебрать стартовое состояние периода K (количество однократных финалистов в начале цикла) - оно же будет являться его концом. Простой динамикой за O(N3) теперь несложно посчитать для каждой пары <C, D> (C - текущее количество однократных финалистов, D - текущий день от начала периода) максимальную вероятность, которую мы можем обеспечить, придя в такое состояние. Ну и из всех возможных пар <K, D> нужно выбрать такую, для которой максимальная вероятность наибольшая.
    Получается, что решение имеет асимптотику O(N4), но константа в таком случае достаточно маленькая, а поэтому решение зашло за 2/3 ограничения по времени.
    • 13 лет назад, # ^ |
      Rev. 5   Проголосовать: нравится 0 Проголосовать: не нравится

      Да... просто.
      С линейным программированием все и правда легко заканчивается.
      Поискал примеры. Вот: решение учатника LayCurse в прошлой правке. Проще положить исходник, чем объяснять.
    • 13 лет назад, # ^ |
        Проголосовать: нравится +5 Проголосовать: не нравится
      Ну, во-первых, от K это решение не зависит: можно считать K нулем (если у нас есть период, то перестановкой действий можно, например, получить неотрицательность количества финалистов на каждом шаге, а также ограничить их количество числом 2N - 1). Амплитуда будет < 2N, значит, период <= 2N, так как повторение количества финалистов не имеет смысла (опять же, можно переставить и получить меньший период). Что Паша и написал.
      Получаем решение за N^3.
      Далее, если доказывать это дело строго, можно получить решение намного проще: возьмем длинный префикс последовательности, мало отличающийся (на eps) от предела "лучшей" последовательности (формально, в условии задачи не было сказано, почему такая существует, но склеивая последовательности, аппроксимирующие супремум, мы ее получим), кроме того, итоговое количество финалистов в котором тоже ограничено константой, не зависящей от длины префикса (из условия возрастания pi можно считать, что такой префикс найдется). Придумаем просто устроенную последовательность, которая хуже разве что на O(eps) и устремим eps к нулю.
      Возьмем пару +T и  - S изменений количества финалистов в префиксе, которая встречается много раз. Если T, S > 0, то можно переставить их так, что подряд идут S прибавлений и T вычитаний, получив тем самым цикл. Проделывая этот трюк далее, мы получим много циклов и маленький остаток (не зависящий от длины префикса). Значит, максимальный по средней вероятности цикл несильно хуже предела, чего мы и добивались: повторяя это цикл с самого начала новой последовательности (для этого еще может понадобиться немного финалистов в начале, это, разумеется, не влияет на предел), получаем последовательность с пределом, равным средней вероятности данного цикла. Так как количество таких циклов конечно, мы доказали, что некоторая последовательность нашего вида является лучшей.
      Решение: перебираем пары  + T,  - S, выбираем ту, которая дает среднюю вероятность лучше (не забываем еще про бесконечную последовательность из  + 0, которая возможна при четном N).
      Итого - N^2.

      Здоровская задача, как, впрочем, и остальные в этом прекрасном раунде.

      P. S. Рассуждение не проверял, поправьте и спросите, если что не так.
13 лет назад, # |
  Проголосовать: нравится +5 Проголосовать: не нравится
E: для компонент вершинной двусвязности это трив (если компонента двудольна, то понятно, иначе - для пары различных вершин всегда можно). Далее - разбиваем граф на компоненты вершинной двусвязности, получаем дерево из этих компонент, смотрим, с какими компонентами пересекается по рёбрам путь в дереве между вершинами запроса - если есть недвудольные, то победа, иначе все пути имеют одинаковую чётность и достаточно проверить какой-то один. Чтобы это быстро проверять, нужно отвечать на lca-образные запросы, например, двоичным подъёмом.
Позже напишу более подробный разбор.
13 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

Может ли проходить такое решениев в В, или я неправильно понимаю задачу? :

Отсортируем все точки сначала по абсциссе, по том по ординате (причем stable). Рассмотрим две соседние горизонтальные прямые, на которых есть точки. Для каждой точки нижней прямой ставим точку с той же абсциссой на верхнюю и наоборот. Пересматривая так по очереди все пары соседних прямых, на которых есть точки, сверху вниз, получим требуемое надмножество. Проблема только в учете повторяющихся точек на последней рассмотренной прямой, что можно реализовать вспомогательным стеком за N2. Если при этом учитывать отсортированность проставляемых точек, то это можно делать за линию, тогда все решение уложится в N*logN за счет сортировок.

Написал, весь контест дебажил и продолжаю (ушел за молотком - выпрямлять руки)

  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    точки которые мы только что сами поставили мы снова размножаем? Если да, то у нас получится до 10в8/2 точек. Если нет то контр тест
    4
    1 2
    2 1
    -2 -1
    -1 -2
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Не размножаем...

      За контр-пример - большое спасибо!