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

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

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

***

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

B. (ссылка) Решение сводится к перебору всех возможных распределений конфет, подсчету вероятности утверждения решения в каждом из случаев с выбором максимума.

Общее количество распределений Ck + n - 1n - 1, что в худшем случае не превосходит 6435. Зафиксируем распределение и вычислим величины zi = min(li + ci × 0.1, 1.0), где zi - вероятность того, что i-ый сенатор проголосует за, li - лояльность сенатора, ci - количество конфет, которые мы отдаем i-му сенатору.

Подсчет вероятности можно делать за время O(2nn), а именно: переберем все маски длины n. 1 будет означать, что соответствующий сенатор проголосовал за, 0 - против. Вероятность получения такой маски равна mmask = П(zi × [i - йсенаторпроголосовалза] + (1 - zi) × [i - йсенаторпроголосовалпротив]), где [true] = 1, a [false] = 0. Теперь для каждой маски найдем вероятность того, что предложение будет утверждено. Оно равно smask = 1 если голосов за больше половины и smask = A / (A + B) в противном случае, где B - сумма уровней сенаторов, что проголосовали против. Таким образом, вероятность для зафиксированного распределения конфет равна .

Решение имеет сложность O(Ck + n - 1n - 12nn).

***

На самом деле изначально эта задача была несколько сложнее (эдак уровня D). Но затем было принято решение ее сильно упростить))

C. (ссылка) В этой задаче нужно было заметить, что если хотя бы в одном предмете занято не все место, то резидентов можно переместить абсолютно любым образом. Это утверждение несложно доказать. Иначе резидентов перемещать вообще нельзя.

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

Итак задача имеет 2 случая: резидентов перемещать нельзя и резидентов перемещать можно.

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

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

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

***

Изначально первый случай задумывался как ловушка и его планировалось поместить в претесты. Но затем, исходя из общей сложности контеста, было решено переместить его в примеры.

D. (ссылка) Эта задача решается с помощью структуры данных система непересекающихся множеств (disjoint set union или dsu) с эвристикой сжатия путей.

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

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

Также нам понадобится ассоциативный массив (вроде std::map в с++), который по цвету возвращает группу из dsu этого цвета.

Еще дополнительно заведем массив размера 2n × 2m, в который сохраним спираль. Ее мы будем использовать для сортировки гео-символов.

Предложенная система структур данных позволяет проэмулировать весь процесс достаточно быстро.

Итак, поместим в очередь начальную пирамидку гео-символа, а также сгенерируем спираль и начальные состояния dsu и ассоциативного массива.

После этого делаем следующее, пока очередь не опустеет:

Извлекаем гео-символ из очереди и нарекаем его текущим. По его координатам на карте через dsu находим группу, в которой он находится и узнаем цвет группы. Далее проверяем цвета группы и гео-символа и определяем нужно ли перекрашивать данную группу.

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

Может оказаться так, что у нас теперь 2 группы одного цвета (это можно узнать из ассоциативного массива). Их нужно объединить а одну - родителем только что перекрашенной группы назначаем вторую группу того же цвета и увеличиваем размер родителя.

Нетрудно понять, что предложенный алгоритм имеет сложность O(nmlognm).

E. (ссылка) Сначала оценим максимальных ответ, что мы можем получить. Он равен 42. Его можно получить из довольно очевидного максимального теста

8 10 10
9 10 10
10 10 10

Общее количество состояний, в котором может находиться персонаж без учета позиции равно 8. 2 состояния ходил/не-ходил умножить на 4 состояния никого-не-держит/держит-А/держит-Б/уже-бросил.

Итого, общее возможное количество состояний равно (8 * 42)3 = 37933056. Такое количество состояний легко умещается в память.

Далее решение представляет собой запуск поиска в глубину или ширину из начального состояния.

Почему это проходит по времени? Ведь из каждого состояния может быть порядка 60 переходов.

Дело в том, что большинство состояний не будет достигнуто. Например, следующие эвристики подтверждают это:
1. Если один персонаж держит другого, то их позиции совпадают.
2. Состояния, в которых одного персонажа держат оба других некорректны.
3. В позициях с большими номерами может находиться не более двух персонажей, а в позициях с очень большими номерами - не более одного.

Кроме того, довольно много состояний, из которых мало переходов. Это те, в которых персонажи уже ходили или уже бросали кого либо.

Более точно количество переходов можно получит написав решение. Запуск на макстесте показал, что переходов всего лишь порядка 2 × 108. Таким образом, решение проходит по времени, нужно лишь аккуратно его написать.

***

Авторское решение на С++ работает около 0,3с. Также есть решения на Java, которые работают 2,8 с и 0,8 с. В первом из них на каждый переход создается новый объект, в итоге несколько раз запускается сборщик мусора, во втором эта проблема устранена. Тем не менее, чтобы решения на Java, подобные первому, проходили, TL был поднят до 3 секунд.

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

13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Спасибо за разбор! Объясните, пожалуйста, где я ошибаюсь в своих рассуждениях по задаче B. В худшем случае у нас 8 конфет и 8 сенаторов с нулевой лояльностью, тогда каждую конфету мы можем распределить 8-ю способами, итого 88 способов всего. И что нужно сделать, чтобы пройти TL в моем решении: http://pastie.org/2373910 ?
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Ну сам посуди, нам же без разницы порядок выдачи конфет.
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Спасибо огромное! Вот оно что оказывается, я перебор писать не умею..(
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Песня группы ИДР "Кривые руки у Кирилла", это про тебя.
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Спасибо, Евгений Ваганович, что указали на мой недостаток! Буду стараться выпрямить их :D
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Thanks for editorial
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Повторяю просьбу к предыдущему оратору - ставьте, пожалуйста, ссылки на задачи
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
В задаче D нет необходимости в dsu: мы все время перекрашиваем одну и ту же компоненту.

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

Поэтому достаточно изначально посчитать для каждого цвета количество гео-панелей данного цвета, далее поддерживать число S - сколько панелей текущего цвета (тот, в который в последний раз перекрашивали) у нас есть. Когда происходит перекраска в новый цвет, мы прибавляем к S количество перекрашиваемых клеток. При этом количество панелей текущего цвета обнуляем. Фактически, так и будет работать решение с СНМ.
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
someone plz tell the precision concept in the first question. Why  we have to add 0.0001 to the quantity(level * coefficient) before comparing it with 100 ?
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    If you read the coefficient as a floating-point number, numbers that are not representable in finite binary digits (0.10, for example) become slightly smaller or larger than they really are.  That's why.
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      so what we should add in these cases 1e-07 or o.0001 is sufficient or we can add anything??
      • 13 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        You can normally use 1e-9
        Let's call it EPS=1e-9
        Just think of it like that(pls correct me if i'm wrong):
        any number within EPS of a float/double number N is considered to be equal to the number(that is if number X is between N-EPS and N+EPS, then X considered equal to N)

        1. For A==B use: abs(A-B)<EPS or equivalently: B-EPS<A<B+EPS
        2. For A<B use: A<B-EPS
        3. For A<=B use: A<B+EPS

        Now for problem A, you need to check:
        K*level < 100
        ==> K*level < 100-EPS
        ==> K*level +EPS < 100, so you can calculate (int) (K*level+EPS) then compare with 100 or also compare directly K*level< 100.0-EPS
        • 13 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          if we want to check only (K*level < 100) no equality case then there is no need of precision but i think here we have to check (k*level <= 100) that's why we will have to take care of the precision.... Am I Correct???
          • 13 лет назад, # ^ |
            Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

            The statement says:"...are strictly less than 100",
            so we need to check K*level<100 NOT K*level<=100
            NO, you need to take care of precision in ALL cases: <,<=,==.
            For A<B you need to do A<B-EPS because we are considering any number between B-EPS and B+EPS to be equal to B. it's similar for A<=B.
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
а в задаче B, если в рекурсию передавать текущее произведение вероятностей и текущую сумму уровней всех проголосовавших против, проверку можно делать за O(1) и сложность решения становится O(Ck + n - 1n - 12n)
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
"In the second case some catch exists. In the three choosen items you can have more empty slots than you had at the beginning of moving. It is impossible because you cannot drop residents. Therefore you should, for example, put as most as posiible unused residents into empty slots of three choosen items."

The editorial suggest that we should retain the residents count within the selected items. Why should we retain the count of residents in the three chosen same as before? Isn't it okay if the number of residents remaining is lesser or equal to the sum of size of the items not selected. This means we can very well accommodate the remaining residents in the items not selected and hence need not maintain the count within the selected three items.