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

Автор yeputons, 13 лет назад, По-русски
Вопросы, предложение, более красивые решения можно и нужно предлагать в комментариях.

Задача A. Лифт


Можно разобрать четыре случая, а можно заметить, что если обозначить front/back за 0/1 (b), а из a вычесть единицу, то a XOR b будет ответом (0/1). Время и пямять - O(1).



Задача B. Что? Где? Когда?


Решается "в лоб" одним циклом: пока k-й вопрос сыгран, увеличить k на один, и, если k > n, то k = 1. Время и пямять - O(n).


Задача C. Винни-Пух и мёд


Одним из решений было написать ровно то, что просят в условии. Итераций Винни-Пуха будет не более 3n (к каждой банке он обращается не более 3-х раз), каждую итерацию можно выполнить за O(n) (поиск максимума в массиве). Время - O(n2) ≈ 104 операций, память - O(n).

Но есть решение короче: давайте заметим, что порядок поедания мёда ни на что не влияет. Теперь посмотрим на то, сколько мёда из каждой банки съест Винни-Пух, а сколько оставит Пятачку. Нетрудно понять, что если ai >  = 3k, то Винни-Пух оставит Пятачку ai - 3k килограмм, а если ai < 3k, то . Теперь решение задачи - один цикл. Время и память - O(n).



Задача D. Три сына


Сначала переберём, какими будут разделяющие прямые - горизонтальными или вертикальными. Чтобы не повторять два раза кусок кода, можно просто повернуть поле на 90 градусов и повторить поиск какого-нибудь одного типа (например, вертикального). Перебираем границы раздела (так, чтобы все области были непустые), считаем суммарное количество кукурузы в каждой области и сравниваем с тем, что надо получить (например, можно отсортировать и сравнивать поэлементно). Если совпало - увеличиваем ответ на 1. Общее время работы - O(n2· m2) ≈ 6.25·106 операций, память - O(nm)



Задача E. Поставь Коня!


Утверждается, что ответ - . При чётных n выигрывает второй игрок (Гена), при нечётных - первый (Петя). В первом случае второй игрок ставит коня симметрично первому игроку (относительно центра поля). Во втором случае первым ходой Петя ставит коня в центр доски, а далее ставит симметрично ходам Гены. Можно понять, что при данных стратегиях выигрывающему игроку не придётся ставить коня под бой. Таким образом имеем решение за O(1) времени и памяти.



Задача F. Паучки


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

Докажем, что лучше нельзя: в самом деле, пусть мы как-то склеили паучков и получили ответ лучше. Посмотрим на самый длинный путь. Он сначала проходит по одному паучку, потом по другому и т.д., причём паучки не повторяются, иначе путь имеет самопересечения. Значит, длина пути не больше, чем сумма длин максимальных путей в каждом паучке, что и требовалось доказать.

Длину паучка можно искать перебором начальной вершины пути и запуском DFS'а. Время работы - операций, кол-во используемой памяти зависит от того, как вы работете с графом. В любом случае, 256 МБ должно хватать.



Задача G. Бум


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



Задача H. Краткость - сестра таланта


Заметим, что всевозможных строк длиной до 4-х символов всего лишь . Это небольшое число. Давайте занумеруем всё такие строки следующим образом: обозначим отсутствующий символ за 0, а символы a..b - 1..26 и посчитаем полиномальный хэш: id(a0 a1 a2 a3) = a0· 273 + a1· 272 + a2· 27 + a3. Заметим, что для всех строчек он будет различен и принимать значения в отрезке [0; 274 - 1 = 531440].

Теперь заметим, что каждую из строк можно заменить максимум на , где (|wi| - длина i-го слова) коротких слов. Давайте построим двудольный граф. В одной доле будет n вершин, соответствующие словам, а в другой доле - все короткие слова. Ребро из a в b проводится в том, и только том случае, если a можно заменить на b. Теперь наша задача свелась к нахождению в этом графе максимального паросочетания и проверке, что в него входят все вершины слева. Это можно сделать алгоритмом Куна. Время работы - O(n1· m), где n1 - количество вершин первой доли, а m - количество рёбер графа. O(n1· m) ≈ 200· 200· 385 = 15.4·106 операций, что прекрасно укладывается. Для сохранения времени работы необходимо хранить граф в виде списков смежности. Т.о. используемая память - O(n1 + m), что также немного.



Задача I. Счастье в числах


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

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

Теперь решение для подзадачи. Оно довольно просто - забъём хвост восьмёрками и посчитаем ответ. Очевидно, что лучше нельзя.

Решение выше хорошо всем, кроме времени работы. Если каждый раз честно пересчитывать максимальный ответ для "хвоста", то время работы будет порядка O(n2). Чтобы измежать этого, можно заметить, что при изменении номера фиксированной цифры на единицу, ответ для хвоста пересчитывается по довольно простым законам, правда, разным для первой и второй половин.

Если добавить пересчёт, решение станет работать за O(n) и требовать O(n) памяти, чего хватает.



Задача J. Минимальная сумма


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

Теперь задача такова: есть n точек на плоскости, надо найти две ближайшие. Это стандартная задача на метод разделяй-и-властвуй. Этот алгоритм описан на e-maxx.

  • Проголосовать: нравится
  • +50
  • Проголосовать: не нравится

13 лет назад, # |
  Проголосовать: нравится +9 Проголосовать: не нравится
В J, если не знать алгоритма с e-maxx, можно было впихнуть вот такое решение, которое попроще будет:
возьмем какую-нибудь далекую точку Х. понятно, что если точки находятся близко, то и расстояние до Х от этих двух точек отличается не сильно. тогда отсортируем точки в по расстоянию до Х. для каждой точки будем просматривать const ближайших.
p.s. как показала практика const = 200 хватает для прохождения тестов =)
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Я по длине векторы отсортировал и искал в окрестности +-100.
13 лет назад, # |
Rev. 2   Проголосовать: нравится +1 Проголосовать: не нравится

Actually, in Problem B F,one can compute the diameter of a tree by doing DFS twice. Let u be an arbitrary vertex of the tree, then obtain the farthest vertex v from u and the farthest vertex w from v by two DFS's. The diameter of the tree will be equal to the distance between v and w.

Anyway, thanks for the nice editorial.

13 лет назад, # |
  Проголосовать: нравится +6 Проголосовать: не нравится
кто-нибудь решал задачу Н куном?
  • 13 лет назад, # ^ |
      Проголосовать: нравится -7 Проголосовать: не нравится
    Да, я набрал -18 пытаясь переиграть составителей тестов, но так и не смог. В конце концов я сел и написал Куна. Ну ничего, отыгрался на задаче J - 1:1 :)
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Решал. Просто пишется же.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    А как можно иначе?
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Я написал именно Куна.
    • 13 лет назад, # ^ |
      Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

      да?) я честно говоря начал читать твой разбор этой задачи, подумал, что что-то примудреное, невнимательно прочитал и даже не заметил, что в итоге к куну все свелось)

13 лет назад, # |
Rev. 2   Проголосовать: нравится +16 Проголосовать: не нравится

По задаче Н можно заметить так же, что для каждого слова не имеет смысла оставлять более 200 его сокращений, так как в любом случае даже если все остальные сокращения этого слова будут использованы одно сокращение останется. Это уменьшает количество вершин в другой компоненте связности до 200*200=40000. И, кстати, такая оптимизация позволяет решить задачу в более общем случае. 

13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Problem C: "..Time and memory consumption is O(n)..." Memory consumption can be easily made O(1)
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Instead of divide and conquer, there's a conceptually simpler scanline + set solution for J.
13 лет назад, # |
  Проголосовать: нравится +8 Проголосовать: не нравится
В задаче "I. Счастье в числах" неплохой подход узнал сегодня (спасиб SAMueL) - будем для текущей строки поддерживать счастливость билета, а при изменении какой-либо цифры пересчитывать за О(1)... вышло очень так неплохо
13 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

В задаче I можно было двумя несложными динамиками:

Первая находит максимальную счастливость при фиксированной первой половине числа (так чтобы конечное число было больше исходного). Вторая находит максимальную счастливость на первой половине (число так же должно быть больше исходного). Ясно что если ответ первой динамики больше текущей счастливости, тогда восстанавливаем правую половину, иначе если вторая динамика больше текущей восстанавливаем первую половину и пересчитав вторую динамику восстанавливаем остаток числа, иначе ответ -1.
Ответ восстанавливается обычным перебором по цифрам за 10*N. Динамики работают за 2*10*N. Код
13 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

Кстати, есть такое решение I: сначала идем с конца строки и заполняем все восьмерками. По фигу, будет ли получаться меньшее или большее число чем раньше - заполняем. Как только мы в каком-то разряде поняли, что наша счастливость стала выше чем была раньшеДалее смотрим: если у нас в этом разряде стояла раньше девятка и, заменив ее на восьмерку, мы получили большую счастливость-то проходим еще несколько разрядов, пока идут девятки. Как только закончили проход влево-начинаем проход вправо таким жадным образом: просто ставим в эту позицию минимальное число, которое может встать в эту позицию. Необходимость и достаточность очевидны. Сложность -О(10*n)

»
11 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Can somebody tell me how to do symmetrical turns in Problem E — Put Knight? Thanks.

  • »
    »
    11 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    If n is even, you can put knight symmetric to the center: if 0 ≤ x < w, 0 ≤ y < h, then our answer move is w - x - 1, h - y - 1.

    If n is odd, our first move is center of the board, the next ones are symmetric, like when n is even.

»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

In problem J, even my distance was int, i still get ac

»
5 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

I am getting a very very weird error. Can someone please tell me why my solution for the problem F is getting run time error on submitting while it is giving correct output on compiling my local editor or codeforces editor. Here is my Submission