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

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

Добрый день!

Только что закончился этап Открытого Кубка.

Давайте поделимся решениями.

Интересуют B,G,F.

Разбор

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

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

Я правильно понял, что в G двумя указателями можно? И если нет, то почему?

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

G: You need some preprocessed array. prevMin, nextMin, prevMax, nextMax. prevMin[i] = j, if j is maximum among such indices that number[i] => number[j]. Similarly others.

Now for each index i, consider the span: (prevMin[i], nextMin[i]) (exclusive range), and find the right most maximum in the range: (prevMin[i], i] and left most maximum in the range: [i, nextMin[i]). These two are possible candidate for maximum and minimum. Say one of these indices is j. Then your answer can be: intersection of: (prevMin[i], nextMin[i]) and (prevMax[j], nextMax[j]).

Take the best among these candidates

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

Точность ТЛей удивляет, можно уже и до сотых было.

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

    В некоторых задачах ведь и было до сотых:)

    Интересно, как именно определяли эти TL. Аккуратно подогнали вручную? Если взять ограничения с pdf с ejudge, и поделить на ограничения на Яндексе, то для разных задач получаются ощутимо различные результаты.

    И еще, у кого более-менее быстро работало решение G — можете показать? Хочу понять, что именно мы делали плохо:) По остальным задачам решения без особых оптимизаций заходили с двукратным запасом, а здесь у нас еле-еле 0.97.

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

      Таймлимиты ставились как 5x от времени запуска лучшего авторского решения (model solution) на c++ на каждой из систем. Запускалось одно и то же решение. Разные отношения TL показывают, что Xeon с Яндекса и Quad Core с OpenTrains работают по-разному, и к простому масштабированию это не сводится.

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

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

        А как объяснить то, что времена работы программы на различных запусках порой очень сильно различаются в Яндекс Контесте? У нас на 5 последовательных посылках в дорешивание задачи J вердикты варьируются от 2.1 ОК до 2.3 TL (и, как поговаривают тут на сборах, это различие бывает еще сильнее). И это то самое решение, которое, как нам кажется, работает локально максимум 0.5 секунд.

        • »
          »
          »
          »
          »
          10 лет назад, # ^ |
          Rev. 4   Проголосовать: нравится +17 Проголосовать: не нравится

          Меня тут попросили приложить некие доказательства, так вот они.

          Задача E1 со сборов в МФТИ. Мое кривое n * lg(n)2 решение с простым кодом: http://pastie.org/private/mlyvxyzzczqi2g3yzdfl3w

          Вердикты на разных запусках: http://i.imgur.com/rBSz4k6.png

          Задача L7 с тех же сборов: http://pastie.org/private/05vj1xwlfdsao9iaypa

          Вердикты: http://i.imgur.com/6d7jWJb.png

          Я не знаю, что там прогревается и как тестируется, но я искренне считаю, что разницы в 35% быть не должно, иначе это приводит к всяким шаманизмам вида "отправим решение 5 раз, авось пройдет".

    • »
      »
      »
      10 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
»
10 лет назад, # |
Rev. 2   Проголосовать: нравится +8 Проголосовать: не нравится

F: построим разбиение на циклы (произвольное), потом помержим соседние циклы пока все не смержится. Как строить разбиение на циклы: достаточно пройтись сверху вниз, добавляя ребра в приоритете "лево", "право", "низ". Это вроде бы доказуемо работает, правда там неприятный разбор случаев, мы на контесте до конца не доказали.

Upd. Translation to English, requested by dragoon.

First, let's construct a set of cycles, and then merge them into a single cycle. Merging is actually quite easy: 2 cycles which have at least 1 neighboring segment can be merged into a single one with a trivial transformation.

So, the problem is reduced to the following: "assign edges so that each cell has exactly 2 edges incident to it" (this is equivalent to constructing a set of cycles). It turns out that this can be done quite easily: iterate over board from top to bottom and add missing edges with the following priority: "left", "right", "bottom". It seems to be provably correct, but there are many cases one needs to take into account in the proof, so we didn't bother with the complete proof during the contest.

»
10 лет назад, # |
Rev. 3   Проголосовать: нравится +8 Проголосовать: не нравится

B. Посортим запросы по ёмкости, пройдём по ним в этом порядке. Понятно, что в каждый момент времени множество заправок — набор компонент связности, которые merge'атся с увеличением ёмкости. Понятно, что моменты merge — это когда мы достигаем минимального расстояния между заправками. Такие event'ы можно по-разному обрабатывать, мы просто для каждого ребра добавили событие (Merge ближайшей заправки левого конца и ближайшей заправкт правого конца, момент времени — (расстояние до левого конца от его ближайшей заправки + расстояние до правого конца от его ближайшей заправки + длина ребра)).

Итого решается за Дейкстру + сортировку.

Upd. Translation to English, requested by dragoon.

Let's sort queries by capacity. For each fixed capacity, the set of stations consists of several connected components; these components merge if capacity increases.

Let's find the moments of merging. Two stations merge when the capacity is equal to the shortest distance between these stations. So, let's iterate over all edges in the graph. Consider edge e = (v1, v2). Let s1 be the closest station to v1, s2 — the closest station to v2. Then, we add event at capacity dist(s1, v1) + dist(s2, v2) + len(e) to merge components of s1 and s2. Note that we're only interested to the closest stations to the ends of each edge.

So, the solution is as follows. Compute shortest distances to all nodes from stations, add events, sort them (together with queries) and process the events with DSU. I.e., the code is just Dijkstra + sort() + DSU.

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

Кто может рассказать E?

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

    Если n не делится на gcd(p, q), то, конечно, игра продлится бесконечно.

    Иначе сначала сделаем вынужденные ходы-прибавления (не более 2), не умаляя общности, ход снова за первым игроком и имеется n камней.

    Пусть n не делится на p, иначе ответ понятен. Тогда, если p < q, то мы всегда можем оставлять не более p - 1 камней и вынудить этим соперника положить ещё ровно q. Тогда за конечное время получится забрать всё (например, из соображений о разрешимости диофантова уравнения px + qy = n).

    Остаётся p > q. Тогда, если мы в какой-то момент оставим хотя бы q камней, то сработает предыдущий случай, но уже для соперника, поэтому надо делать единственно возможный ход в от 0 до q - 1 камней (если он есть, иначе мы проигрываем). Останется n mod p камней. Далее по той же логике их количество станет уменьшаться на p - q, поэтому, если n mod p делится на p - q, то мы победим, иначе инициатива будет передана противнику.

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

Может ли кто-нибудь рассказать, как решать С? Нужно было как-то усовершенствовать простое ДП по маске товаров и числу рассматриваемых магазинов?

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

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

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

      Спасибо!

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

      А как учитывать что можно получить одинаковую цену из различных магазинов?

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

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

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

          Пока писал что я имею в виду, понял что это что-то нереальное.

          Спасибо, зашла.

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

            Кстати, можно действительно написать динамику по маскам и магазинам:) Получится n * m * 2m. Почти так же, как и стандартная динамика "какой лучший ответ для маски х, если использовали только первые у магазинов", но дополнительно храним в маске 0/1 — покупали мы уже что-то в текущем магазине или нет. Тогда если пытаемся купить при 0 в этом флажке — к цене товара прибавляется цена посещения самого магазина.

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

              А как получается n·m·2m?

              Пусть мы сейчас в магазине N, и у нас есть маска M. В этом магазине можно купить любую комбинацию товаров, которые еще не были куплены. Получается, если K товаров не куплены, то есть 2^K вариантов что-либо купить.

              Суммарно выходит вроде n·3m У вас есть код? Как делать переход за O(m)?

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

                Так переходы ведь будут по одному предмету, а не сразу на произвольную маску — если К товаров не куплены, то есть К вариантов перехода-покупки.

                Исходный код.

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

                  Понятно,cпасибо! Я писал что-то похожее, но в состоянии динамики зачем-то еще хранил последний купленный предмет. Получалось O(2m * m2 * n), и Time Limit Exceeded.

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

Как решать K?

Я делал граф из отдельных координат по иксу и по игреку, соединял рёбрами соседние координаты. Плюс добавлял нулевые рёбра вида X-Y из ввода. Ну и находил кратчайший путь из начальных координат в конечные. Это TL10.

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

    Для каждой вершины не больше четырех ребер нужно добавить: отсортировали по иксу — добавили соседей и аналогично по игреку.

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

      Действительно, можно было и так. Спасибо.

      Обидно. Асимптотика та же самая.

      UPDATE: Оказывается дело было в алгоритме поиска кратчайшего пути. Первый раз он меня так подвёл. Поменял на дейкстру с e-maxx.ru и получил AC.

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

In div.2 I tried to solve O (or N in my pdf problem set). About Hacktris. How did you solved it? I tried slow variant — O(W*H), but have a mistake at 27 testcase. Can't find my mistake — http://ideone.com/W6eUNZ (Perl)

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

I guess only remaining are H, I and J. Any thoughts?

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

    J. Let's choose some root. For each speleologist, let's compute the highest node in the tree which he can reach on his path (LCA + binary ascent, or how is it called in English). These nodes should form a chain, otherwise the answer is "NIE". Let's take the lowest node from the chain and check it (2 LCA per speleologist). If all the checks pass, we know the answer otherwise the answer is "NIE".

    So, we have 3 LCA and 1 binary ascent per speleologist, which fits in TL if implemented carefully.

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

    You can find analysis here.

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

Немного не в тему — согласно правилам зачета от Яндекса, 15 ноября должны были подвести итоги первой стадии (которая только для NEERC). Сегодня уже 16, итоги еще не подвели, или я плохо искал?

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

need upsolving ...