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

Автор Connector, 13 лет назад, По-русски
Задача А.

Введем вспомогательное определение. Полупустой квадрат — это такой изначально пустой квадрат, в который положили печеньку максимально возможного размера.

Заметим, что, если добавить в полупустой квадрат размера 2n × 2n печеньку максимального размера (она будет иметь размер 2(n - 1)), то наш квадрат разобьется на 4 квадрата величины 2n - 1 × 2n - 1, три из которых будут полупустыми квадратами, а один будет полностью заполнен. Отсюда следует формула f(n) = 3 * f(n - 1), f(0) = f(1) = 1. Переходя к замкнутой форме, получим ответ 3n - 1 (при n > 0) и 1 (при n = 0).

Задача B.

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

Задача C.

Для начала научимся решать более простую задачу: требуется подсчитать количество счастливых билетиков, в которых 1 ≤ a ≤ x и 1 ≤ b ≤ y. Преобразуем выражение a * b = rev(a) * rev(b) к выражению вида a / rev(a) = rev(b) / b. Переберем все возможные a и подсчитаем кол-во обычных несократимых дробей вида a / rev(a) (double, кстати, тоже работает =) ) с помощью какой-нибудь структуры, например, map из STL. Остается для каждого значения b найти количество совпадающих дробей a / rev(a) с rev(b) / b и добавить к ответу.

Теперь перейдем к нашей задаче.

Если счастливых билетов с ограничениями 1 ≤ a ≤ maxx и 1 ≤ b ≤ maxy меньше w, то x и y, удовлетворяющих условию задачи, не существует и следует вывести  - 1
Если решение существует, то воспользуемся методом двух указателей. 

Нам потребуется поддерживать количество счастливых билетов 1 ≤ a ≤ x и 1 ≤ b ≤ y. Для этого заведем две структуры типа map (назовем их m1 и m2). Научимся переходить из состояния (x,y) в состояния (x,y+1), (x+1,y), (x,y-1), (x-1,y). Если мы хотим увеличить (уменьшить) значение x, то к значению количества счастливых билетиков мы прибавим (отнимем) m2[x/rev(x)] и увеличим (уменьшим) значение m1[x/rev(x)] на единицу. В случае с изменением y следует выполнить аналогичные действия.

Зафиксируем некоторое состояние (x,y), где x = maxx, а y = 1 и подсчитаем для него количество счастливых билетиков. Будем увеличивать y, пока баланс счастливых билетиков не станет больше или равен w. Очевидно, что это будет такое наименьшее y для x, что в соответствующем диапазоне найдется достаточное количество счастливых билетов. Важно отметить, что в дальнейшем уменьшать y не будет иметь смысла. Прорелаксируем ответ и уменьшим x на единицу. Будем повторять действия, описанные в этом абзаце, пока x больше нуля. 

Так как x из ответа лежит в пределах от 1 до maxx и для кадого значения x из этого же диапазона мы нашли оптимальное значение y, то в результате работы алгоритма был просмотрен ответ с наименьшим значением x * y.

Так как каждый указатель не принимает одно значение дважды, и время, затрачиваемое на поддержку баланса, порядка логарифма, то общее время работы программы имеет асимптотику O(maxx * log(maxy) + maxy * log(maxx)).

Задача D.

Заметим что любая точка, лежащая внитри треугольника из первых трех точек, будет всегда содержаться внутри выпуклой оболочки в дальнейшем. Зафиксируем одну из таких точек и перенесем центр координат в нее. Будем хранить точки выпуклой оболочки в структуре типа map, где ключом будет угол для вектора из начала координат к какой-либо точке. Каждому углу будет соответствовать одна точка.

Научимся отвечать на запросы второго типа. Для точки в запросе (A) найдем ближайшую точку к ней по часовой (B) и ближайшую против часовой (C) стрелки. Если угол, образованный векторами AB и AC отрицательный, то точка лежит вне выпуклой оболочки, в противном случае точка лежит внутри или на границе. 

Теперь научимся обрабатывать запросы первого типа. Если точка из запроса (C) лежит внутри выпуклой оболочки, то ничего делать не надо. Найдем две ближайшие точки по часовой стрелке (ближнюю из них обозначим A, другую B). Если поворот от вектора AB к вектору AC положительный, то закончим обработку точек по часовой стрелке, иначе удалим из структуры точку A и повторим эти же действия. Подобным образом следует обработать точки, лежащие против часовой стрелки относительно C. 

Каждая точка добавляется максимум один раз и удаляется максимум один раз. Каждая из этих операций выполняется за O(log(h)), где h — количество точек в выпуклой оболочке. Итоговая асимптотика O(q * log(h)).

Задача E.

Заметим следующие факты. Пусть у нас есть зафиксированное состояние некоторого количества областных центров, тогда для каждой вершины не являющейся, областным центром следует выбрать ближайший к ней областной центр, т.к. d[i] <  = d[i + 1]. Утверждается что все вершины лежащие между некоторой вершиной x и ее центром g будут принадлежать этому центру g. Предположим что это не так, тогда g является не самым ближайшим центром для некоторой вершины между x и g, и для нее существует более ближайший центр u, но тогда должно быть dist[x][u] < dist[x][g], что приводит нас к противоречию. Таким образом получаем, что наше дерево должно быть разбито на некоторое количество поддеревьев и в каждом поддереве будет один областной центр. Для общности так же положим d[0] = 0.

Будем решать задачу используя "перекрестное" ДП.

Первая функция DP. D1(T, g, x, s) будет отвечать за формирование поддерева с областным центром g. T -- некоторое поддерево исходного дерева определяемое направленным ребром uv. областной центр g должен содержаться в T. Будем считать что городу v назначен областной центр g. Так я упомянул выше эта функция будет отвечать за формирование дерева с цетром g. Вся задача будет заключаться в выборе тех ребер которые будут ограничивать наше поддерево. Рисунок:

Зеленые и красные ребра соединяют вершины, которым назначен областной центр g. Фиолетовое ребро ограничивает множество вершин, которым назначен центр g. Стоит отметить, что вершины лежащие на пути из красных ребер нельзя использовать как ограницивающие т.к. вершине v уже назначен центр g.

Пусть ребро xs является ограничивающим, тогда для поддерева T' (Вершины этого поддерева обведены в круг) вызовем функцию функцию ДП D2(T').

Вторая функция ДП будет перебирать каждую вершину в поддерве T' в качестве областного центра и вызывать D1.

В первой функции ДП имеется порядка O(n3) состояний т.к. поддеревьев T порядка O(n), вариантов выбора g столько же и пара (x;s) образует ребро, а ребер всего 2*n-2. Вторая функция ДП имеет O(v) состояний и переход выполняется за O(v). Таким образом решение требует O(n3) памяти и имеет асимптотику O(n3).

Разбор задач Codeforces Beta Round 64
  • Проголосовать: нравится
  • +65
  • Проголосовать: не нравится

13 лет назад, # |
Rev. 2   Проголосовать: нравится +3 Проголосовать: не нравится
О, ошибку исправили:)
Спасибо за разбор.
Только разнос между сложностями сегодня великоват, как по мне. Мало людей с 3+ задачами.
  • 13 лет назад, # ^ |
      Проголосовать: нравится +3 Проголосовать: не нравится
    ну поспешил человек, а ты придираешься =/

    тут вон, например, есть слово "замнуктой" и ничего страшного, пусть сперва автор суть донесёт, а потом очепятки исправит
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
В B я написал простое ДП, n=255 позволяло. Вообще почему-то, если есть возможность написать ДП, я его пишу. Жадность только если вообще нет никаких идей :)
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Я написал очевидную жадность, получил ВА7, подумал - мало-ли что... может, из-за жадности. Быстренько переписал на динамику, и только после второго ВА7 понял, что не в жадности проблема, а в том, что я не только первый пробел удалял, но и все остальные пробелы в СМС, если перед которыми был конец предложения. 
    • 13 лет назад, # ^ |
      Rev. 2   Проголосовать: нравится +1 Проголосовать: не нравится
      Кстати, очень сильные претесты. Я ошибся точно так же, рад что претесты помогли вовремя поправиться. А ведь можно было устроить такой рай хаккерам=)
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Похоже, вы технарь :D Я про "---".
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
О различных пожеланиях по поводу уточнения некоторых моментов в разборе и очепяток буду рад услышать в личку. =)
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
В задаче C у большинства я увидел использование дерева Фенвика, как ее можно применить при решений этой задачи?
  • 13 лет назад, # ^ |
      Проголосовать: нравится +3 Проголосовать: не нравится

    Может, так?

    Перебираем x от 1 до maxx. А y будем искать бинпоиском. Для этого нам бы надо знать массив a[1..maxy] - т.е. a[i] - каков будет ответ, если мы возьмём y=i (понятно, что в терминах задачи a[i] - количество хороших серий для данного билета). Подбирая минимальное y бинпоиском, мы ищем такой префикс массива a, на котором сумма будет >=w. А переходя от x к x+1, мы должны увеличить значения в некоторых ячейках массива (в тех билетах, которые сочетаются с серией x+1). В общем, две стандартные операции на дереве Фенвика - сумма на префиксе и изменение значения.

    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      O(maxx * (log(maxy)) ^ 2)? Удивительно, как это в TL укладывается... Наверно только на C++.
      • 13 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        Ну известно, что Фенвик имеет очень быстрый логарифм, так что ничего удивительного. Да и бинпоиск только штук 17 итераций сделает. Итого где-то 10^5 * 17*20 - т.е. около 40 млн., что весьма мало.

        Но я не писал, это только предположения

        • 13 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          Ну просто сделать так - это первая мысль, которая у меня возникла. Но всё-таки подумал, что на Java это в TL не уложится, и судя по существующим решениям оно б так и было (они на C++ больше 2 секунд работают). Потому решил, используя heap - и даже в ML уложилось :)
13 лет назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится

В E у меня решение за квадрат (наверное, как и у многих - судя по временам работы).

Пусть d[v][p] - ответ для поддерева с корнем в вершине v, если ближайший сверху областной центр находится на расстоянии p. Тогда у нас могут быть такие варианты:

а) мы ставим в d[v][p] областной центр, тем самым переходя за стоимость k в состояние d[v][0]

б) мы не ставим в d[v][p] областной центр, и все областные центры в наших потомках находятся на расстоянии p или более - тогда сыновья являются независимыми, и мы просто суммируем d[child][p+1]

в) мы не ставим в d[v][p] областной центр, но среди потомков есть областной центр на некотором расстоянии q<p - тогда выходит, что этот сын будет влиять на всех остальных, т.е. фактически для остальных сыновей всё будет получаться, как будто бы мы пришли в вершину v с расстоянием q. Чтобы посчитать значение по переходу этого вида, мы перебираем q и сына, в поддереве которого это q находится, и от этого сына запускаем вторую динамику (d2[v][q] - это ответ, если на расстоянии <=q от v обязан быть областной центр), а от всех остальных сыновей и самой вершины v - ответ считаем как в переходе б), как если бы в вершину v мы пришли с расстоянием q.

Весь переход в), чтобы он быстро делался, можно оформить как третью динамику d3[v][q] - она пробует делать третий переход для q, а ещё берёт ответ из d3[v][q-1]. Ну а как делать за O(deg[v]) переход при фиксированном q, наверное, понятно (стандартный приём, что посчитаем сначала сумму нужных величин по всем сыновьям, а затем при переборе выбираемого сына будем выкидывать из этой суммы одно слагаемое).


Вот, выглядит наверное жестковато, но мне как-то было просто рассуждать вот так, поэтапно. Уверен, что эту же идею можно было оформить и без трёх динамик :)

  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Интересная задача. А где можно найти задача на эту идею? что бы закрепить ето дело :)
13 лет назад, # |
Rev. 2   Проголосовать: нравится +1 Проголосовать: не нравится
thank's for your very good Analaysis. ;)
13 лет назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится
Can anyone explain why in problem D this is true "Note that any point lying vnitri triangle of the first three points will always be contained inside the convex hull in the future". Thanks
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Hi,

Sorry, I dont really understand the analysis and have a few questions. Hope that you can help me out. Thanks!

Problem D:

May I know why the first three points of the input will definitely be in the convex hull? Is such an input impossible?

1 1 0
1 0 0
1 0 1
1 -1 2
1 2 -1
1 -1 -1

In such an input, the convex hull will be (-1,2) (-1,-1) (2,-1).

Also, for the queries B and C, how do you find the nearest point anti-clockwise and clockwise? Which line of reference do you take to determine whether a point is clockwise or anti-clockwise? And may I know how do you find the nearest point efficiently?

Problem E:

I am not too sure about the DP state definition :(.

I think that what you are saying that first, you root the tree. Then, suppose the edge uv is bounding. Then you are going to get a subtree T, which is bounded by the edge uv. In this subtree, you choose g as the regional centre. Then you try each edge and try to set it as a bounding edge for the next subtree. Suppose you have chosen the edge xs. Then you recursively work on this new subtree. You call DP 2 to bruteforce which vertex should be regional centre be located at. Then you call DP 1 again. So say you call the next subtree T' and the node you are building regional centre p. Then you will call DP1 (T', p, x, s).

Is this what you are saying? Please correct me if I am wrong.

Also, may I know how do you represent a subtree in your DP state? And it seems to me that given any tree, there are a lot more than N different subtrees (for example, given a line graph I think there are about N^2 different subtrees. There are about N^2 different sets of endpoints you can choose from, and each set defines a unique subtree). Am I missing something here?

Sorry, I am new to this kind of DP, so my questions might sound a bit obvious XD. Thanks a lot!
13 лет назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится

D.

UPD: any point from the triangle based on first three points will be into the area bounded with the convex hull in the future.

To find the nearest point efficiently use binary search tree (if you write in C++ you can use map class).

E.

Yes, you understood what I mean. You should recursively bruteforce xs edge. T is represented in next way: edge uv divides tree into two subtrees, T is one of these subtrees containing vertex v.


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

    Thanks for your reply! I think I understand how to do problem D now.

    But I am still not too sure about problem E. I dont quite understand the function DP 2. What does it store? Does DP 2[x] store the min cost if you build a regional centre at x? But won't the answer be different if your subtree is different? What is the recursion for DP 2 like?

    Thanks in advance again!
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      D2[T'] store the minimum cost of the maintaining the subtree T'. Let's T' be represented with the edge uv using the way described in previous post. Bruteforce all the vertexes in the sebtree T'. Let the vertex g will be fixed, let's say that it is some regional center assigned to v. Call the D1(T',g,g,0 (the first neighbour)) and relax the answer for the D2[T'] with the returned value.