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

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

Сегодня состоится Московский четвертьфинал-2013. Интернет-тур пройдёт также на системе ejudge, но на серверах Открытого Кубка. Соответственно, участвовать могут все команды, которые получили логины Открытого Кубка. Старт Интернет-тура в 11-00.

Также на задачах Интернет-тура (и самого четвертьфинала) будет проведено несколько матчей нового экспериментального проекта — Кубка Сборных. В этом турнире участвуют сборные, состоящие из 5 команд. В каждом туре участвующие сборные разбиваются на пары, после чего оказавшиеся в одной паре сборные играют между собой матч по правилам "Матча Гигантов", прошедшего на ЧУ-2013. За выигрыш по сумме задач сборная получает 3 очка, за выигрыш по суммарному штрафному времени при равном числе задач — 2 очка, за проигрыш по суммарному штрафному времени при равном числе задач — одно очко, за проигрыш по задачам — 0 очков.

Вход в систему (напоминаем, что тур стартует в 11-00 по московскому времени).

Жеребьёвка Кубка Сборных, состав сборных и окончательная формула будут опубликованы позднее.

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

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

А нельзя было заранее, хотя бы за сутки объявить об интернет-туре? Ни на официальном сайте, ни на сайте Открытого Кубка, ни на Snarknews никакой информации накануне не было.

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

А где текущие результаты посмотреть?

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

А можно будет потом написать виртуально?

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

А задача А как решалась?

  • »
    »
    11 лет назад, # ^ |
      Проголосовать: нравится +3 Проголосовать: не нравится
    1. Если n < 3, то ответ — 0.
    2. Треугольники вычитают из степеней каких-то вершин либо (1, 1, 1), либо как (2, 1, 0).
    3. Если есть элемент x такой, что x > 2·(sum - x) (т.е. он больше 2/3 от суммы), то избыток бесполезен. "Урежем" элемент. После этого новых избыточных элементов не появится.
    4. А теперь ответ — sum / 3. Можно либо послать, либо как-то доказать в стиле "если есть элемент больший половины, то (2, 1, 0) к трём наибольшим, иначе (1, 1, 1) к трём наибольшим".
  • »
    »
    11 лет назад, # ^ |
      Проголосовать: нравится +8 Проголосовать: не нравится

    Можно было просимулировать. Возьмем 3 вершины с максимальным значением. Если у них у всех значения одинаковые, вычтем из всех по единице, иначе — вычтем из максимального 2, а из второго максимального 1. Будем повторять пока можем, прибавляя каждый раз 1 к ответу. Главное было это каждый раз за О(1) делать.

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

Будет ли открыто дорешивание?

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

Как K решалась?

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

    Сгенерируем последовательность два раза. За первый раз узнаем старшие 16 бит ответа. Для этого нужно 216 интов, это мало памяти. Просто храним сколько чисел с такими старшими битами и в конце прошлись и посчитали.

    За второй раз числа делятся на те, которые точно идут в ответ, те которые точно не идут в ответ, и те у которых 16 бит совпали. С последними разбираемся так же, как считали первые 16 бит.

    Мне одному показалось, что боян?

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

      Мы делали не так. Будем генерировать последовательность и записывать ее в массив. Как только размер массива стал 1.5 миллиона, применяем nth_element, оставляя только k максимальных чисел, после чего опять дописываем числа к получившемуся массиву. Работает меньше секунды на макстесте.

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

      Да, задача уже давалась на московском четвертьфинале 2004 года под буквой J, но с другим форматом входных и выходных данных. Один боян на контест — это же не много :)

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

        Об этом я не знал. Зато есть вот такое. Или имеется ввиду, что там сильно больше всего проходит?

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

          Ну на тимусе можно сдать кучу. Память же у кучи линейная, вот только время n log n.

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

      Я автор этой задачки.

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

      Изначально я предполагал под правильным решением именно то, что написал KADR, правда вовсе не обязательно делать буффер именно на 1.5 миллиона чисел, 2k чисел вполне достаточно(хотя с 1.5 миллионами, теоретическая константа будет меньше).

      Интересный факт, что вызвать nth_element на массиве из 100000000 миллионов чисел у меня в среднем работает чуть медленнее, чем пройтись по последовательности так, как описал KADR. Думаю, что дело в работе с кэшом.

      В последствии оказалось, что сделать так, чтобы именно такое решение требовалось от участников очень сложно, так как если потребовать, чтобы задача была решена за один проход по последовательности, нужно было бы откуда то читать эти числа, а чтение откуда угодно этих чисел слишком трудоемкая операция, чтобы отделить O(n) от O(nlogn) на остальные операции.

      К моему великому сожалению, 95% команд решило задачку именно чем-то типа сортировкой подсчетом(хотя, например, две команды ветеранов, которые прорешивали контест предварительно пользовались другими идеями).

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

А где можно условия посмотреть?

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

А есть таблица после разморозки? Или она до весны замерзла?

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

    У нас еще награждение идет, таблицу на онсайте не разморозили.

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

Как C решалась?

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

    (наблюдение 0: p2 и α нужны только чтобы ответ компактно выводить)

    Наблюдение 1: если на каком-то отрезке вероятность константна, то это просто частота на этом отрезке (если в сторону частоты сдвинуть не получается из-за монотонности, то выгодно смёрджить с предыдущим/следующим отрезком).

    Наблюдение 2: если есть какое-то решение, и какой-то отрезок в нём можно подразбить, то его всегда выгодно подразбить.

    Итого, делается за линейный проход со стеком. Ну или можно более интуитивно проинтерпретировать: заменяем 0 на вектор (1, 0), 1 — на вектор (1, 1), и последовательно идём вдоль этих векторов; получаем ломаную. Из наблюдений 1-2 понятно, что надо найти нижнюю огибающую к ней.

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

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

      P.S. Я понимаю, что вроде интуитивно похоже на правду и уже пора засылать -- это вполне себе ответ на мой вопрос. Всё же хотелось бы "честный ответ".

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

        В терминах геометрической интерпретации:

        1 => решение — это какая-то ломаная, вершины которой — подмножество вершин исходной ломаной; монотонность => ломаная выпукла вниз. Осталось понять, почему точки под ломаной — не выгодны. Посмотрим на какую-нибудь точку под ломаной, посмотрим на отрезок AB над ней, заменим его на AX и XB; при этом что-то могло сломаться с монотонностью. Надо показать, что если выкинуть все отрезки после B с наклоном меньше XB (то же самое для A), то целевой функционал не увеличится (с учётом подразбиения AB). Вот тут заканчивается геометрия и начинается страница вычислений :( Хотя возможно есть и красивое геометрическое объяснение, надо спросить у авторов.

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

А где дорешать можно?

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

А как решалась G(интерактивка)? Я правильно понял, что когда количество слонов отрицательно в input'е, то я могу купить/продать меньше, чем abs(x) (где x — количество слонов в input'е)?

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

    Какое условие было: У вас есть два типа действий: sell и buy. На каждой итерации аукцион меняет какое-то своё состояние и вам нужно в этом новом состоянии заработать как можно больше денег.

    Понимание приходит после разбора семпла: 1 итерация: аукцион готов купить 10 слонов по 100, мы слонов купить никак не можем, прибыль 0.

    2 итерация: аукцион готов продать 4 слона по 98 и купить 10 по 100. Тогда мы эти 4 покупаем, продаем по 100, прибыль 8.

    3 итерация: аукцион готов продать 4 слона по 98 и купить 3 по 100. Тогда теперь только 3 покупаем, продаем по 100, прибыль 6.

    4 итерация: аукцион готов продать 4 слона по 98, купить 3 по 100 и 2 по 99. Прибыль: 1*(99-98)+3*(100-98) = 7

    5 итерация: аукцион готов продать 1 слона по 97, 4 слона по 98, а купить 3 по 100 и 2 по 99. Прибыль: 1*(99-97)+3*(100-98)+1*(99-98)=9

    Окей, давайте теперь придумаем хотя бы какое-то решение.

    Утверждается, что работает такая стратегия: давайте возьмём два вектора: предложений sell и buy, отсортируем по стоимости его элементы, а затем будем покупать самых дешевых слонов, продавать их за как можно дороже, постепенно так сходясь двумя указателями, то есть один идём с префикса sell, другой с суффикса buy, пока либо не кончатся слоны где-то, либо стоимость продажи станет <= стоимости покупки, то есть профита от сделки мы уже не получим.

    И это работает за O(M * M * lg(M)), где M -- количество запросов, что очень много. Давайте соптимайзим.

    У нас есть, по сути, две медленных операции:

    1) Нам нужно как-то уметь поддерживать два посортированных по стоимости вектора.

    2) Нам нужно как-то быстро проходить двумя указателями, чтобы получить прибыль.

    Давайте научимся делать это быстро.

    Понятно, что для первой операции мы можем использовать какое-нибудь дерево. Можно взять декартово, и тогда просто сплитать его, и вставлять на нужное место наш новый элемент, или уже изменять значение у старого, если такая цена уже в нём была. Я на контесте ленивое дерево отрезков написал, потому что писать проще, то есть мы создаем дерево отрезков на 10^9 (максимальная цена операции), а узлы его создаем только по мере необходимости.

    В итоге, я умею первую операцию делать очень просто за O(lg(109)) -- просто изменяя значение в соответствующем узле дерева отрезков/дд.

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

    Сразу проверим, что это количество меньше либо равно чем минимальное количество слонов в векторах buy и sell, иначе не получится никак.

    Ок, допустим мы зафиксировали это количество.

    Понятно, что мы теперь хотим купить слонов подешевле, а продать их подороже, поэтому нам интересен некий префикс вектора sell и суффикс вектора buy.

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

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

    Ну и прибыль наша считается тривильно, мы считаем сумму на префиксе в дереве, сумму на суффиксе, чуть-чуть их изменяем, потому что на префиксе/суффиксе могло быть не ровно k слонов и выводим разницу.

    В итоге, вторая операция у нас работает за O(lg(262) * lg(109)).

    Как-то жутко в описании получилось, на контесте выглядело проще :)

    Видимо, второе действие можно без бин. поиска сделать, просто одним спуском, но заходило и так.

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

      у большинства лишний бинпоиск не прокатывал вместо спуска, правда, он обычно был по цене

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

        А как делать спуском за ? Мы подумали пару минут, получилось что-то относительно страшное, забили.

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

          Да всё тоже самое, спускаемся по цене, слева больше — идём вправо, справа больше — идём влево, на нижнем уровне добавляем объём или его часть по этой цене либо к праву либо к леву, в зависимости от того где больше, только при спуске пересчитываем не всё с нуля, а с учётом значений предыдущего шага

          Я так понимаю, что дихотомия по объёму может проходить, поскольку начинаем не с 2^62, а с текущего минимума двух объёмов, он намного меньше, может просто теста не хватило с совсем небольшими ценами но очень жирными объёмами

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

            Не понял. Нам требуется найти что-то страшное: такое максимальное k, что k-й элемент слева в одном дереве не больше, чем k элемент справа в другом дереве.

            Может, есть пример кода?

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

              как-то так Но здесь цифровой бор.

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

              дерево можно сделать одно и считать в нём четыре параметра

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

                Согласен, по сути это есть одно дерево:-) просто мне так понятнее было писать.

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

      Спасибо! Очень подробно и понятно!)

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

Где есть результаты виртуального тура?