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

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

Представляю полный разбор задач Codeforces Round #153. Если возникнут какие-то вопросы или пожелания -- пишите в комментариях, постараюсь ответить.

252A - Маленький xor (A div 2)

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

252B - Разупорядочивание массива (B div 2)

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

Кажется, что этот алгоритм работает за O(N3). На самом деле это не так и его время работы можно оценить как O(N). Дело в том, что если есть хотя бы 3 пары позиций с различными числами, то одна из них обязательно подойдет. Это связано с тем фактом, что всего существует 2 различных отсортированных массива (по убыванию и по возрастанию), а все пары позиций с различными числами после обмена дают различные массивы. Следовательно, один из трех различных массивов обязательно будет не отсортированным.

252C - Точки на прямой (C div 2)

251A - Точки на прямой (A div 1)

Переберем правую точку из тройки, при этом будем поддерживать указатель на самую левую точку, которая отстоит от текущей на расстояние не большее, чем d. Мы легко можем определить количество точек внутри отрезка между двумя указателями (не включая правую точку). Обозначим это количество через k. Тогда ясно, что существует ровно k * (k - 1) / 2 троек точек, в которых самая правая точка совпадает с текущей, которую мы перебираем. Осталось просуммировать ответы для всех таких точек.

252D - Игра с перестановками (D div 2)

251B - Игра с перестановками (B div 1)

В начале проверим, совпадает ли перестановка s с тождественной. Если совпадает, то ответ "NO".

Теперь приведем алгоритм, который работает во всех случаях, кроме одного. О нем будет сказано позже. Будем применять прямую перестановку (в условии она обозначается как q) до тех пор, пока текущая перестановка не совпадет с s, либо пока мы не сделаем k шагов. Если текущая перестановка совпала с s, то посмотрим на количество ходов, которые мы уже сделали (обозначим его через t). Если число k - t четное, то мы можем выбрать любую перестановку в нашей последовательности, кроме предпоследней и применять к ней (k - t) / 2 раз связку "обратная перестановка + прямая перестановка". Это можно не выполнять явно, просто достаточно проверить четность числа k - t. Итак, если оно четное, то ответ "YES".

Аналогично, попробуем применять обратную к q перестановку до тех пор, пока мы не получим перестановку s, либо пока не сделаем k шагов. И опять, если мы получили перестановку s, то проверим четность оставшегося количества ходов и в случае, если это количество четно -- выведем "YES". Можно понять, что в противном случае ответ "NO".

Приведенный выше алгоритм работает для всех случаев, кроме одного: когда перестановка q совпадает со своей обратной перестановкой, причем перестановка s достижима за один ход. В этом случае, если k = 1, то ответ "YES", иначе ответ "NO".

Полученный алгоритм работает за время O(N2).

252E - Превращение числа (E div 2)

251C - Превращение числа (C div 1)

Обозначим через L наименьшее общее кратное всех чисел от 2 до k. Заметим, что если a кратно L, то мы не сможем уменьшить его операцией второго типа. А это значит, что в оптимальной последовательности превращений будут присутствовать все числа, кратные L, которые находятся между b и a. Разобьем все числа от b до a на отрезки между числами, кратными L. Может выйти так, что первый и последний отрезки будут не полными. Видно, что достаточно решить задачу для первого и последнего отрезка, а также решить задачу для любого отрезка между ними, после чего последний результат нужно еще умножить на количество отрезков между крайними. Осталось только сложить полученные 3 числа и вывести ответ.

Также требовалось аккуратно рассмотреть случаи, когда у нас есть всего 1 или 2 отрезка.

Сложность решения O(L).

251D - Два множества (D div 1)

Обозначим xor всех чисел через X. Также, обозначим xor всех чисел в искомом первом наборе через X1, а во втором наборе -- через X2. Заметим, что если i-й бит в числе X равен единице, то i-е биты в числах X1 и X2 равны либо 0 и 1, либо 1 и 0, соответственно. Аналогично, если i-й бит в числе X равен нулю, то i-е биты в числах X1 и X2 равны 1 и 1, либо 0 и 0, соответственно. Как видим, на сумму X1 + X2 влияют только те биты, которые в числе X равны нулю. Пока забудем про то, что от нас требуется минимизировать число X1 и найдем максимальную возможную сумму X1 + X2.

Для того чтобы найти X1 + X2 сделаем еще одно наблюдение. Рассмотрим старший бит числа X, который равен нулю. Если существуют такие разбиения исходного набора на два, в котором этот бит равен единице в числе X1, то оптимальное разбиение обязательно должно быть одним из них. Чтобы доказать это, вспомним что соответствующий бит в числе X2 также равен единице. Обозначим соответствующую этому биту степень двойки через L. Тогда, если в числах X1 и X2 этот бит равен единице, то даже в том случае, когда все остальные биты равны нулю, сумма X1 + X2 равна 2L + 1. Если же в рассматриваемый бит мы в X1 и X2 поставим ноли, то даже в случае, когда все остальные биты равны единице, сумма X1 + X2 будет равна 2L + 1 - 2, что меньше, чем 2L + 1. Утверждение доказано.

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

Итак, для набора условий осталось научиться проверять, существует ли хотя бы одно разбиение, которое удовлетворяет всем этим условиям. Для каждого условия на бит с номером i составим уравнение над полем Z2 с n неизвестными, в котором коэффициент при каждой переменной равен i-му битчисла с соответствующим ей номером. Если неизвестная равна единице, то соответствующее число мы берем в первое множество, иначе -- во второе. Полученную систему уравнений можно решить алгоритмом Гаусса. Заметим, что нам не нужно каждый раз при добавлении нового уравнения решать всю систему с нуля. Достаточно лишь за O(NK) пересчитать матрицу из предыдущего состояния. Здесь, K -- количество уравнений в системе.

Итак, мы научились находить разбиение с максимальной суммой X1 + X2. Минимизировать X1 можно аналогичным образом: будем идти по всем битам, которые равны единице в числе X, начиная со старшего. Для очередного бита будем пытаться поставить в число X1 ноль. Если после этого система уравнений перестала иметь решение, то в соответствующем бите ставим единицу, иначе -- оставляем ноль и переходим дальше.

Сложность полученного алгоритма равна O(NL2), где L -- битовая длина максимального из чисел. Для дальнейшего ускорения можно использовать структуру bitset в алгоритме Гаусса, хотя этого не требовалось для получения Accepted на контесте.

251E - Дерево и таблица (E div 1)

Если N = 1, то существует ровно 2 укладки дерева на таблицу.

Если в дереве есть вершина, степень которой превышает 3, то ответ 0. Это связано с тем, что любая клетка таблицы имеет не более трех соседей.

Если в дереве нет вершин степени 3, то ответ 2 * n2 - 2 * n + 4. Эта формула выводится естественным образом при дальнейшем решении задачи. Также, можно было написать простую динамику для решения задачи в случае, когда у всех вершин степень 1 или 2. Так или иначе, давайте докажем приведенную формулу.

Для начала, решим немного другую задачу, которая будет использоваться при решении основного случая. Найдем количество способов уложить дерево на таблицу при условии, что в дереве нет вершин степени 3, а также одна вершина степени 1 прикреплена к левому верхнему углу таблицы (будем считать, что это вершина номер 1). Можно показать, что если размер таблицы 2xK, то количество способов укладки дерева равно K. Доказывать это будем по индукции. Для K = 1 утверждение, очевидно, выполняется. Для K > 1 будем доказывать следующим образом. Предположим, что таблица ориентирована горизонтально, т.е. у нее 2 строки и K столбцов. Если вершину, соседнюю с первой, мы поставим правее от нее, то потом у нас есть только один способ расположения дерева. Если же мы поставим ее снизу от первой, то следующую вершину мы обязаны поставить правее от нее, т.е. в клетку (2, 2). Теперь, мы получили ту же задачу, только K стало на единицу меньше. Таким образом, мы получили рекуррентное соотношение: f(K) = f(K - 1) + 1 и начальное условие f(1) = 1. Легко видеть, что в этом случае f(K) = K.

Итак, теперь вернемся к исходной задаче: сколько существует способов расположить дерево без вершин степени 3 на таблице 2xN. Без ограничения общности, предположим, что первая вершина дерева имеет степень 1. Будем рассматривать только те варианты, в которых первая вершина лежит на верхней строке таблицы, после чего просто умножим ответ на 2. Итак, если первая вершина лежит в первом или последнем столбце, то, как мы уже выяснили, существует N способов расположить на таблице оставшееся дерево. Если же первая вершина лежит в столбце с номером i (нумерация начинается с единицы, левый столбец имеет номер 1), то существует i - 1 способ, в котором соседняя с первой вершина лежит справа от нее. Также, существует N - i способов, в которых соседняя с первой вершина лежит слева от нее. Просуммировав это для всех столбцов и умножив ответ на 2, получим окончательный результат: 2 * n2 - 2 * n + 4.

Итак, остался самый главный случай, когда в дереве есть вершина степени 3. Объявим такую вершину корнем и подвесим дерево за него. Если существует несколько вершин степени 3, то в качестве корня мы можем выбрать любую из них. Предположим, что корень лежит в первой строке таблицы, а потом просто умножим ответ на 2. Ясно, что корень будет лежать на клетке, имеющей трех соседей. Переберем, какой из потомков корня будет лежать слева от него, какой будет лежать снизу, а какой -- справа. В случае, если потомок, лежащий снизу от корня, имеет степень 2 или 3, нам нужно еще перебрать, какой из его детей пойдет влево, а какой -- вправо. Всего есть не более 12 вариантов расположения потомков корня и потомков его "нижнего" сына. Итак, теперь у нас занят весь столбец, в котором лежит корень, а значит, как бы мы ни укладывали дерево дальше, все вершины, лежащие справа от корня там и останутся лежать. Аналогично, все вершины, лежащие слева от корня, там и останутся. Мало того, у нас есть фиксированное количество вершин слева и справа от корня, а значит, у нас есть ровно один вариант его расположения на таблице. Заметим, что если слева от корня находится нечетное количество вершин, то дальше дерево мы уложить не сможем. Посчитать количество вершин можно, просто сложив размеры поддеревьев для его потомка, а также потомка его "нижнего" сына, которые находятся слева от корня.

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

1) Нам нужно уложить поддерево с корнем в вершине v на прямоугольную таблицу, причем вершина v находится в углу таблицы (для определенности будем считать, что это левый верхний угол).

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

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

Покажем, как свести задачу второго типа к задаче первого типа. Итак, если у вершины v1 или v2 есть 2 потомка, то ответ 0. Если у них по одному потомку, то мы можем перейти в них и получить ту же самую задачу. Если у обоих вершин нет потомков, то мы уже покрыли всю таблицу, так что ответ на задачу равен 1. Если же у одной вершины нет потомка, а у второй вершины один потомок, то мы получили задачу первого типа для этого потомка.

Итак, нам осталось решить задачу первого типа. Обозначим через f(v) количество способов уложить поддерево с корнем в вершине v на прямоугольную таблицу. Размер этой таблицы однозначно определяется из размера поддерева. Для решения задачи нам нужно рассмотреть 2 случая:

а) Вершина v имеет степень 2.

б) Вершина v имеет степень 3.

В случае, если вершина v имеет степень 2 и в ее поддереве нет ни одной вершины степени 3, то f(v) = s(v) / 2, где s(v) -- размер поддерева с корнем в вершине v. Ранее мы уже доказывали эту формулу. Теперь, предположим что в поддереве вершины v есть хотя бы одна вершина степени 3. Если таких вершин несколько, выберем ту, которая ближе всего к v. Обозначим ее через w. Итак, есть 2 варианта:

а.1) Путь из вершины v в вершину w пойдет так, что предпоследняя вершина в пути лежит слева от w.

а.2) Путь из вершині v в вершину w пойдет так, что предпоследняя вершина в пути лежит сверху от w.

Третьего варианта нет, поскольку у вершины w степень 3, а если мы "обойдем" ее так, чтобы предпоследняя вершина на пути лежала справа от w, то при этом клетка над w также будет занята, что сделает невозможным правильное расположение всех соседей вершины w.

В каждом из вариантов а.1) и а.2) переберем, куда идут потомки вершины w (одно направление уже занято ее предком, так что остается ровно 2 свободных направления). В случае, если потомок степени >1 идет вниз, требуется также перебрать, куда идут какие его потомки (есть 2 варианта: вправо и влево). После этого, справа от вершины w опять получается задача типа 1) или 2), которые были сформулированы выше. Слева от вершины w у нас есть дерево либо не укладывается вообще, либо укладывается однозначно. Это можно проверить исходя из длины пути из v в w, а также размера поддерева внука вершины w, который пошел в тот же столбец, что и w (если такой внук вообще есть). Осталось просуммировать ответы для всех этих вариантов.

Итак, задачу типа а), когда вершина v имеет степень 2, мы решать уже умеем. Осталось решить задачу б), когда вершина v имеет степень 3. Для этого достаточно перебрать, какой из ее потомков пойдет вправо, а какой — вниз. После этого получаем задачу либо типа 1), либо типа 2), которые были сформулированы выше.

Итоговая сложнось решения O(N).

Разбор задач Codeforces Round 153 (Div. 1)
Разбор задач Codeforces Round 153 (Div. 2)
  • Проголосовать: нравится
  • +34
  • Проголосовать: не нравится

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

Просек

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

    Его получать не надо, это просто чтобы представлять проще было. А так — мы применяем прямую перестановку до тех пор, пока не нашли искомую или пока не сделали K шагов. Если мы нашли перестановку Маши и при этом у нас осталось четное количество шагов, то выводим ответ "YES". После этого пробуем сделать то же самое с обратной перестановкой. Если и тогда не получилось, то выводим "NO".

    Это решение работает неправильно всего в одном случае: когда прямая перестановка равна обратной, причем искомая перестановка достижима за 1 шаг. Такой случай можно отдельно в начале программы разобрать.

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

В задаче B сдал такое решение за O(k2n): сохраним в a[i][j] единицу, если после i применений первой перестановки и j применений второй перестановки получается перестановка s, иначе a[i][j] равно нулю. Теперь надо проверить, что существует путь от (0,0) до (i,j), где i+j == k, a[i][j] == 1 и сумма на этом пути равна единице (ходить можно, увеличивая одну из координат на единицу).

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

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

    Сумма на пути равна 1? Почему? Там же надо чтобы в (i, j), где i + j == k не просто вел путь весом 1, а путь, содержаший эти единицу в точности в ячейке (i, j).

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

      Там еще написано: a[i][j] == 1. Значит, на остальном пути 0.

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

    А каким образом Вы проверяли наличие пути с суммой = 1 ? Я написал обход в глубину с запоминанием: шёл в (i-1,j) и (i, j-1) (если там нули), а если добрался до (0, 0), то значит путь есть.

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

      Ну это настолько стандартная задача, что даже не хочется отвечать.

      Стартуем из (0,0): s[0][0] = a[0][0], остальные значения s заполняем бесконечностями.
      Далее в двух вложенных форах делаем две операции:

      • s[i+1][j] = min(s[i+1][j], s[i][j] + a[i+1][j])
      • s[i][j+1] = min(s[i][j+1], s[i][j] + a[i][j+1])
»
11 лет назад, # |
  Проголосовать: нравится -14 Проголосовать: не нравится

В C(Div2)A(Div1) у меня зашло такое решение: будем идти двумя указателями по массиву точек, изначально первый равен нулю. сдвигаем второй пока расстояние не превысит d. Попутно будем считать oldp — точки который в данный момент входят в подмассив ограниченный нашими указателями, а newp точки которые добавились с момента последнего превышения d. Тогда при превышении d прибавляем к ответу newp*cnk[oldp][2]+oldp*cnk[newp][2]+cnk[newp][3]. Сдвигаем первый указатель на единицу вперед и присваиваем oldcnt=oldcnt-1+newcnt, а newcnt=0. Если расстояние не превысило еще d, то просто увеличиваем newp на единицу.

Решение Вот такое курево о_О

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

is there editorial in English?

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

Div1 C: Что если между числами A и B не лежит число, кратное LCM? В таком случае нужно получить из числа (B mod LCM) число (A mod LCM), не так ли?

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

    У меня была функция make(int l, int r), которая возвращала минимальное количество ходов, необходимое для получения из числа r число l. В программе писал так:

    if (a — b < t) { cout << make(b, a); return 0; }

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

В D проще всего выглядит решать так. Для начала, поймем, что для Маши второе условие — при равных максимум. Будем решать задачу для нее. Переупорядочим биты так, чтобы сначала шли нулевые в общем ксоре, а потом единичные в общем ксоре. Таким образом, задача стала такая: дано множество чисел, найдите помножество, ксор которого наибольший. Последнее — крайне известная штука, Гаусс там реализуется без построения матрицы.

2714253

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

is there editorial about Div1.E ?

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

For the Problem A div 2 — i saw two kind of solutions.

In this code below it iterate over all segments in our array. For each of them we'll find the xor of all its elements. Then we need to output the maximal xor we've seen. code 2744731

In this code it does not do that and only find some of those. code 2702002

can anyone please tell me the deference of these two. Why is the second one correct. Why we need not to iterate over all segments.

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

    Both solutions are iterating over all possible segments. The only difference is that the second one does it more efficiently. One can notice that the xor of all elements from the segment [a, b] is equal to the xor of all elements from [a, b — 1] xor the value of element on the b-th position. Thus, we don't need to calculate the xor of every segment from scratch, as we can use the values for the segments we've already processed.

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

DIV 2 PROBLEM B : "One may notice that in every array of length greater than 3 there are at least 3 pairs of different numbers"__ i do not understand this part .... suppose there ara two different numbers on the array and they are X and Y .... the rest positions of the array is filled with X. then we get : X X (X) X X (Y) X X X ..... here we get only two different pairs ... like : (X,Y) and (Y,X) as (X,X) is invalid for swapping .... then what does the line actually means .. ??

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

Is there an O(N) solution for problem A div 2 ?

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

    well there exists an O(N * log(max number)) solution by using trie like the idea in problem 282e

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

For Div 2 E, will anyone please explain why this statement is true — " It means that any optimal sequence of transformations will contain all numbers divisible by L which are located between b and a." It is written in the editorial.

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

    Suppose we managed to skip some number X divisible by L, which lies between B and A. Let Y be the last number from our sequence that is greater than X. There exists a number k such that . However, L < Y and , which means that . We've got a contradiction, thus every number divisible by L, which lies between B and A should be in our sequence.

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

Can someone explain the solution of Div1 D with an example as how to use Gaussian elimination in finding the answer ??

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

in div 2 c could anyone explain why he use the equation (k*(k-1)/2) instead of using combination C(n,k)

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

can we use dp in A div2?

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

Why kC3 (where k is the length of segment satisfying the constraint) is giving wrong answer for problem Div1 A ?