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

Автор pyloolex, история, 8 лет назад, По-русски

На последнем контесте была задача D. Кай и снежинки. В разборе написано, что вполне подойдет решение в каждой вершине сливать сеты ее потомков.

Очевидно, что худший тест — это просто цепь из 300000 вершин. Тогда получается, что в каждой вершине будет 1, 2, 3,..., 300000 элементов в сете. Всего элементов (арифм. прогрессия) 300000 * 300000 / 2 ~= 45 * 10^9.

Это катастрофически много. Когда я попытался именно сохранить все эти сеты, то, разумеется, получил ML. Однако, если написать как в разборе, то есть просто запуститься рекурсивно из корня и постепенно получать ответ для него (не сохраняя сами сеты), то получим Accepted.

Так вот по сути же выделяем под те же 45 * 10^9 интов. Единственное, что приходит в голову, то что сет после выполнения функции чистит за собой память, которую потребовал в ходе выполнения этой функции, и в последствии может снова использовать ее же.

1) Подскажите, это правда так?

Грубо говоря, есть цикл for (int i = 0; i < 100000; i++) { set a; a.insert(3); }

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

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

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

set a — локальная переменная, видная только в блоке после цикла фор. Как только область видимости этой переменной заканчивается, она уничтожается и вызывается деструктор. Надо смотреть как у сета написан деструктор. Ну скорее всего он должен все очищать.

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

    А codeforces как оценивает потребляемую память? Может ли этот цикл выполняться 1е15 раз(если не брать в расчет ТЛ)? Или получу вердикт ML?

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

      можно хоть сколько да. вот смотри, например такой код (основной код в функции солв) в запуске на кф и у меня локально выводит два одинаковых адреса. т.е он и в первый и во второй раз разместил переменную в одном и том же месте.

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

        Круто! Я раньше думал, каждое выделение памяти засчитывается как новое. Спасибо!

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

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

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

В вашем примере, даже если считать суммарное кол-во выделенной памяти, её все равно не квадрат, а nlogn (а иначе бы был TL все равно, вы просто не успевали бы потрогать всю выделенную память)

И да, вы TL получали, а не ML до изменения