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

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

532A - Шахтёры Берляндии

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

532B - Рабочая группа

Эту задачу можно решить с помощью динамического программирования по поддеревьям иерархии сотрудников. Обозначим за D[v][e] максимальную эффективность, которую можно получить, взяв некоторое количество сотрудников из поддерева человека v, таким образом, чтобы их количество имело чётность e, и условие задачи выполнялось для всех взятых людей. Тогда нетрудно пересчитать D[v][e] через детей вершины v с помощью подсчёта промежуточной величины T[i][e] — максимальной эффективности, которой можно достичь, пройдя первые i поддеревьев вершины v, если чётность количества взятых людей — e.

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

532C - Игра на доске

Рассмотрим три случая.

1) xp  +  yp ≤  max(xv,  yv). В этом случае Поликарп может оказаться в (0,  0) через xp  +  yp ходов и Василий всегда будет "позади". Для Поликарпа достаточно делать любой возможный ход, и это приведёт его к победе. Нетрудно это объяснить тем, что условие xp  +  yp ≤  max(xv,  yv) будет выполнено и после любых возможных ходов Поликарпа и Василия. Иными словами, Василий просто не может победить.

2) xp ≤ xv, $y_p \leq y_v$. В этом случае Поликарп должен некоторым образом блокировать Василия. Он должен совершать такой ход, чтобы после любого возможного хода Василия неравенство было снова выполнено.

  • Если xp  =  xv  >  0, нужно пойти в (xp  -  1,  yp).
  • Если yp  =  yv  >  0, нужно пойти в (xp,  yp  -  1).
  • В противном случае можно совершить любой допустимый ход.

Действуя по такой стратегии, мы снова не даём Василию возможности выиграть.

3) В противном случае рассмотрим любой кратчайший путь для Василия до точки (0,  0). Любая клетка этого пути ближе к Василию, чем к Поликарпу, поэтому Поликарп никак не может помешать Василию на этом пути. А значит, Василий дойдёт до финиша первым. Альтернативное объяснение заключается в том, что Василий всегда может сходить таким образом, чтобы ни одно из условий 1) и 2) не оказалось выполненным.

532D - Колонны

Первое наблюдение: колонна рушится только если расстояние между её соседями больше, чем 2di, поэтому для неё не имеет значения, где именно она находится на отрезке между своими соседками. Важно только расстояние между ними.

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

Медленный подход: для каждой предыдущей колонны проверим, может ли она быть соседом C. Ближайшая колонна, которая может, является будет тем самым левым соседом C.

Более быстрый подход: давайте обозначим за far[i] наибольшую возможную координату, где может находиться правый сосед колонны i. В нашей динамике заведём стек с возможными кандидатами на то, чтобы быть левым соседом каждой колонны. В этом стеке колонны будем поддерживать в порядке возрастания индекса (а, значит, и координаты) и одновременно в порядке убывания far[i] (действительно, нам незачем хранить в стеке колонну, если её мажорирует и по координате, и по far[i] какая-то другая колонна).

Теперь для каждой новой колонн мы должны удалить с вершины стека некоторое количество колонн со слишком малым значением far[i]. Последняя оставшаяся колонна на стеке будет той самой, через которую мы пересчитаем значение нашей динамики. Эта часть занимает O(n) времени.

Если существует колонна с far[i] не меньше координаты правой несущей колонны, то ответ--- 0, так как конструкция исходно устойчива.

Теперь посчитаем ту же самую величину справа налево. Теперь некоторые колонны связаны с левой несущей, некоторые — с правой. Мы хотим поставить новую так, чтобы попасть в пределы far[i] как для левой колонны, так и для правой. Это можно сделать, используя технику двух указателей по двум образованным стекам.

Описанное решение работает за O(n) времени и памяти.

532E - Исправление ошибок

Предположим для определённости, что S получается из W удалением более раннего символа, чем T. Тогда W  =  A  +  x  +  B  +  y  +  C, S  =  A  +  x  +  B  +  C, T  =  A  +  B  +  y  +  C, где x и y — удаляемые символы, а A, B и C — какие-то (возможно, пустые) строки.

Определим A как наибольший общий префикс S и T, а C — как наибольший общий суффикс. Удалим их из обоих строк. Теперь мы знаем буквы x и y — это соответственно первая буква строки S и последняя буква строки T. Удалим и их тоже. Остаётся лишь проверить, равны ли оставшиеся части строк.

Проделаем так для S и T, а также для T и S.

532F - Кодирование

У этой задачи возможно два направления решения.

Зафиксируем пару букв x и y. Заменим в строке S все буквы x на единицы, а все остальные буквы на нули. В строке T заменим все буквы y на единицы, а все остальные буквы на нули. С помощью алгоритма КМП или Z-функции определим все позиции, в которых строку T можно приложить к строке S так, что они совпадут. Если такое условие выполнено как для пары букв (x, y), так и для пары букв (y, x), то это значит, что в данной позиции можно приложить T к S с заменой x <-> y и возможно ещё какими-то заменами.

Теперь для каждой позиции надо проверить, разбиваются ли буквы на пары в соответствии с известной нам информацией. Это можно сделать за O(sigma), где sigma  =  26 — размер алфавита. Таким образом, решение работает за O(n  *  sigma2  +  n  *  sigma)  =  O(n  *  sigma2). Это решение при должной аккуратности реализации проходит по времени.

Другой способ — произвести замену, которая позволит нам сравнивать строки с точностью до переименовывания букв. Заменим каждую букву на расстояние до предыдущей такой же в обоих строках. Теперь для совпадения с точностью до переименования достаточно проверить, что строка T совпадает с подстрокой строки S во всех позициях кроме, возможно первых вхождений каждой буквы в T. Это можно сделать с помощью модифицированной префикс-функции или хеширования.

Пусть мы теперь знаем, что в некоторой позиции строка T совпадает со строкой S с точностью до переименовывания. Нетрудно определить, какая перестановка букв соответствует этому переименовыванию (достаточно посмотреть на первую букву каждого вида в T, чему она соответствует в S). Проверим, что эта перестановка — это набор транспозиций за O(sigma). Таким образом, получим решение за O(n  *  sigma).

Разбор задач VK Cup 2015 - Раунд 2
  • Проголосовать: нравится
  • +123
  • Проголосовать: не нравится

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

532B дважды написано, 532D ни разу (хотя её разбор есть)

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

На самом деле, первое решение задачи F тоже работает за O(N·sigma), если при зафиксированной паре букв (x, y) ходить не по всем буквам строки, а только по этим двум.

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

Как именно нужно модифицировать z/префикс-функцию в задаче F?

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

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

    11 5
    abacabadaba
    acaba
    
    

    получится

    s:  a b a  c  a b a  d  a  b   a
    vs: 2 2 2 inf 2 4 2 inf 2 inf inf
    ---------------------------------
    t:  a  c  a  b   a
    vt: 2 inf 2 inf inf
    

    В z-функции: пусть сравниваем символы t[i] и s[j]. Если vs[i] = vs[j] или vt[i] = inf, то все ок, увеличиваем размер текущей подстроки. В общем, изменение от стандартной z-функции только во втором условии.

    z-функция для первого теста:

    a c a b a ! a b a c a b a d a b a
                5 0 5 0 5 0 5 0 2 0 0
                a c a b a
                    a c a b a
                        a c a b a
                            a c a b a
    
»
10 лет назад, # |
  Проголосовать: нравится +10 Проголосовать: не нравится

Can anyone explain his solution for problem A?

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

    Let us define "cave effective height" as minimum of cave's height and all that cave ancestors' heights.

    First, let's analyze the problem if we cannot increase cave's height. Consider two miners a and b with heights ha > hb and two caves p and q, with p being an ancestor of q. If (in one solution) we assign a to q and b to p, notice, that we can swap them. So following greedy approach works: Assign miners in height decreasing order. Each time choose for the miner the cave, which parent is already filled and with largest effective height from all caves satisfying the first condition.

    If we find the solution, no cave height needs to be raised. Otherwise, we got miner, which doesn't fit in any of the caves that left.

    I claim, that if solution to the original problem exists, we will increase one cave to his height. There is no need to raise any cave more, and we still cannot assign him anywhere if we raise any cave less. Also, we know, that all caves filled before had their heights no lower, so we need to raise height of the cave, that has its parent already filled.

    We are now left with m miners h1 > ... > hm. Now let's maintain sequence x1 - 1, x2 - 2, ..., xm - m, where xk is the number of caves that can fit miners hk, ..., hm. We will be changing heights of some caves. If at some moment, all sequence elements are non-negative, we can assign all miners, so we got the solution. We can use segment tree to store this sequence (we need operations: add constant to interval, get global minimum). Now all that's left is to try to increase (one at a time) height of a cave, that has its parent already filled and check for all effective heights changes. Each cave affect caves only in its subtree.

    Total complexity:

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

    My solution for A:

    1. USACO-step: sort all miners by height.

    2. For each cave calculate the "blocking cave". The blocking cave for some cave V is the cave which you definitely need to increase in order to increase the effective height of the 1-V path. Basically the blocking cave for V is the lowest cave on the 1->V path (1 and V included). If there are multiple caves with the smallest height on that path pick arbitrary, it doesn't matter.

    3. For each cave V calculate the maximum possible path height. This is the height which you can achieve by making its blocking cave to have infinite height. And this value is simply the second minimum height on 1->V path. If V is a root itself then this height is Infinity.

    4. Group these maximum possible path heights by blocking cave index. Each such group will give you an information of what cave heights you might achieve if you increase this particular blocking cave's height to some new value.

    5. Obviously if you increase a height in one group then path heights in all other groups will remain equal to the height of their blocking cave.

    6. Sort all groups by their blocking cave's height.

    7. Do the final magic:

    I claim that if you want to check what is the minimum height you can assign to some group X so that all miners will have a home then you can check that with the rest of the caves being assigned greedily and that will give you the correct result. One more detail for assigning heights greedily. For all groups coming before X you assign shortest available miners, so effectively all you need to remember is how long will be a prefix of people that you will be able to cover with all groups coming before X. For all groups coming after X you try to assign the tallest fitting guy to the cave.

    You see that the right part of that greedy assignment is a bit more complicated than the left one because the suffix of assigned miners might not be contiguous. For that reason it makes sense to iterate over groups in reversed order, starting with the group where blocking cave has maximum height. Then you know which prefix of people you will be able to assign to the groups coming before your current group and all you need to check is whether you will be able to assign remaining people to your current group if you increase its blocking cave's height somehow. You can easily do that in time proportional to the number of caves in this group. After you check this particular group you will move to the right part with regards to the group you will check next, so before leaving your current group you use all its caves with their current height (which are equal to the blocking cave height, since it won't be increased anymore) to put into each cave the tallest fitting miner.

    That was wordy. My submission — 10924081.

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

I think something wrong here.. ?

In problems F, the first idea, with this example: 5 5 acdff adcgh

If we check pair(c,d) => the string S and T: 01000 and 01000; and check(d,c): 00100 and 00100 => chose position 1; but position 1 is not true???

Sorry for my bad english :D

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

I think something is wrong here..?

In problem F; the first idea, with this example: 5 5 acdff adcgh

if we check (c,d), the string S and T: 01000 and 01000; and we check (d,c), the string S and T: 01000 and 01000

=> chose position 1 (according to the solution) ; but it is not true.

Sorry for my bad English! :D

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

    No, we don't choose (x,y) pair directly after this first step, we only mark this position as this may be the answer, and we should check later whether this position is real answer or not, about that it is said that it can be done in "O(sigma) where sigma = 26 — the size of the alphabet" but I don't have any idea yet how it's done in O(sigma).