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

Автор MrLolthe1st, 6 недель назад, По-русски

Div2A

Алёна счастлива, когда нет незавершенных слоев — то есть перед ней идеальный квадрат с нечетной длиной стороны. Поскольку порядок кусочков фиксирован, достаточно отслеживать общий текущий размер $$$s$$$ головоломки и после каждого дня проверять, является ли $$$s$$$ идеальным квадратом нечетного числа. Самый простой способ сделать это — создать дополнительный массив, содержащий $$$1^2, 3^2, 5^2, ..., 99^2$$$, и проверять после каждого дня, находится ли $$$s$$$ в этом массиве.

Код

Div2B

Найдите символ, который появляется наименьшее количество раз — если есть ничья, возьмите более ранний символ в алфавите. Найдите символ, который появляется наибольшее количество раз — если есть ничья, возьмите более поздний символ в алфавите. Затем замените любой из символов с наименьшим количеством вхождений на символ с наибольшим количеством вхождений.

Код

Div2C

Мы можем разделить столбцы в матрице на три разные группы:

  1. столбцы, в которых мы проходим через верхнюю ячейку;
  2. столбцы, в которых мы проходим через нижнюю ячейку;
  3. столбцы, в которых мы проходим через обе ячейки.

В третьей группе должен быть ровно один столбец — это будет столбец, где мы переходим из верхней строки в нижнюю строку. Все остальные столбцы могут быть распределены между группами $$$1$$$ и $$$2$$$ так, как нам угодно: если мы хотим поместить столбец в первую группу, мы поставим его перед столбцом, в котором мы идем вниз; в противном случае мы поставим его после столбца, в котором мы идем вниз. Таким образом, мы можем получить любое распределение столбцов между первой и второй группой.

Теперь давайте рассмотрим вклад каждого столбца в ответ. Столбцы из первой группы добавляют $$$a_{1,i}$$$ к ответу, столбцы из второй группы добавляют $$$a_{2,i}$$$, столбец из третьей группы добавляет оба этих значения. Таким образом, мы можем перебрать индекс столбца, в котором мы идем вниз, взять $$$a_{1,i} + a_{2,i}$$$ для него, а для всех остальных взять $$$\max(a_{1,j}, a_{2,j})$$$. Это работает за $$$O(n^2)$$$, и в ограничениях задачи этого достаточно.

Но можно решить задачу быстрее — за $$$O(n)$$$. Для этого посчитаем сумму $$$\max(a_{1,j}, a_{2,j})$$$ по всем столбцам. Затем, если мы выберем $$$i$$$-й столбец как столбец, через который мы идем вниз, ответ будет равен этой сумме плюс $$$\min(a_{1,i}, a_{2,i})$$$, поскольку это будет единственный столбец, в котором мы посетим обе ячейки.

Код

Div2D

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

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

  • Какое наименьшее число может стоять в начале нашего результирующего массива? Конечно, минимум. Это означает, что все элементы перед минимумом должны быть перемещены назад и увеличены на один.
  • Какое наименьшее число мы можем иметь на втором месте, учитывая, что у нас есть минимум на первых позициях? Либо наименьший элемент справа от минимума, либо наименьший элемент среди тех, кто уже перемещен назад.
  • ...

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

Таким образом, ответ всегда состоит из нескольких первых элементов последовательности минимумов суффикса, начиная с глобального минимума, а затем всех остальных элементов, увеличенных на $$$1$$$ и отсортированных в возрастающем порядке. Чтобы найти точку, где мы переключаемся от последовательности минимумов суффикса к перемещенным элементам, удобно предварительно вычислить минимумы и сохранить множество тех элементов, которые мы уже переместили вправо.

Это решение работает за $$$O(n \log n)$$$, наряду со многими другими.

Code

Div1C

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

Переберем все нужные нам координаты вертикальных прямых. Для этого заметим, что есть смысл перебирать только те, у которых прямые совпадают по Y-координате хотя бы с одной из точек. Очевидно, что в таком случае необходимых нам вертикальных прямых будет порядка $$$O(n)$$$.

Во время перебора вертикальной прямой мы будем поддерживать два дерева отрезков на сумму: одно для левой половины плоскости и второе для правой. $$$t_y$$$ в каждом из деревьев отрезков будет означать, сколько есть точек с Y-координатой $$$y$$$ в соответствующей половине плоскости. В каждом из деревьев отрезков посмотрим, можно ли разделить половину плоскости на две части прямой, параллельной оси абсцисс, так, чтобы в обеих частях было хотя бы по $$$k$$$ точек; и, если сделать это можно, то найдем множество подходящих прямых — очевидно, это будет некий отрезок $$$[y_{l}, \, y_{r}]$$$. Если пересечение получившихся отрезков в обоих деревьях отрезков не пустое, то мы нашли ответ. Сделать это можно спуском по дереву за время $$$O(\log n)$$$.

Итак, итоговое время работы описанного решения есть $$$O(n \log^2 n)$$$.

Код

Div1D

Сожмем граф в компоненты сильной связности. Внутри компоненты каждый гонец может перемещаться между любыми парами вершин и тем самым посетить все. Будем теперь решать задачу уже для ориентированного ациклического графа.

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

  • каждая вершина принадлежала хотя бы одному пути;
  • в каждой вершине начиналось не больше $$$a[i]$$$ путей (где $$$a[i]$$$ — количество гонцов, изначально находящихся в вершине);
  • пути могли пересекаться.

Возьмем исток $$$s$$$ и сток $$$t$$$, путь же теперь можно представить как последовательность $$$s$$$, $$$u_1$$$, ..., $$$u_k$$$, $$$t$$$.

Разделим $$$u$$$ на $$$u_{in}$$$ и $$$u_{out}$$$ и будем считать, что вершина принадлежит $$$u$$$ хотя бы одному пути, если был хотя бы один переход из $$$u_{in}$$$ в $$$u_{out}$$$. Проведем следующие ребра:

  • из $$$s$$$ в $$$u_{in}$$$ с пропускной способностью $$$cap = a[u]$$$;
  • из $$$u_{in}$$$ в $$$u_{out}$$$ с $$$cap = inf$$$ и условием потока через ребро $$$f \geq 1$$$;
  • из $$$u_{out}$$$ в $$$t$$$ с $$$cap = inf$$$;
  • из $$$u_{out}$$$ в $$$v_{in}$$$ с $$$cap = inf$$$ для всех рёбер (u, v) в исходном графе.

Что и эквивалентно нахождению потока с ограничениями в данном графе.

Для этого создадим фиктивный исток $$$s'$$$ и сток $$$t'$$$, теперь для каждого ребра $$$(u_{in}, u_{out})$$$ c потоком через него $$$1 \le f \le inf$$$ сделаем следующую замену, проведя ребра:

  • из $$$u_{in}$$$ в $$$u_{out}$$$ с $$$cap = inf - 1$$$;
  • из $$$s'$$$ в $$$u_{out}$$$ с $$$cap = 1$$$;
  • из $$$u_{in}$$$ в $$$t'$$$ с $$$cap = 1$$$;
  • из $$$t$$$ в $$$s$$$ с $$$cap = inf$$$.

Нахождение потока удовлетворяющего ограничениям эквивалентно нахождению максимального потока из $$$s'$$$ в $$$t'$$$, и если он равен количеству вершин, то значит ответ гарантированно существует, иначе можно вывести $$$-1$$$ уже на этом шаге.

Теперь минимизируем количество гонцов, которым изначально известен план. Заметим, что:

  • нет смысла гонцам перемещаться, пока не узнают план;
  • нет смысла передавать план более чем одному гонцу из одного города.

Пробуем учесть это при построении. Вместо добавления рёбер из истока в $$$u_{in}$$$ поступим так:

  • создадим вершину $$$u_{cnt}$$$ для контроля количества гонцов и проведём рёбра:
  • из $$$s$$$ в $$$u_{cnt}$$$ с $$$cap = a[u]$$$;
  • из $$$u_{cnt}$$$ в $$$u_{out}$$$ с $$$cap = a[u]$$$;
  • из $$$u_{cnt}$$$ в $$$u_{in}$$$ с $$$cap = 1$$$, $$$cost = 1$$$.
  • всем остальным рёбрам зададим нулевую стоимость.

Что в свою очередь эквивалентно тому, что в результате все $$$a[i]$$$ гонцов узнают план, но, если в наш город никто не пришел, то собственноручно расскажем ровно одному гонцу из этого числа заплатив при этом $$$cost=1$$$ человека.

Ответом на задачу является минимальная стоимость максимального потока из $$$s'$$$ в $$$t'$$$ при таком построении графа. Доказательство следует из построения графа.

MCMF можно считать за $$$O(n^2m^2)$$$ или $$$O(n^3m)$$$ для любых графов, но в стоит заметить, что величина потока f ограничена n и имеем решение за $$$O(fnm)$$$ при использовании Форда-Беллмана или $$$O(fm\log n)$$$ при использовании Дейкстры с потенциалами.

Из интересного, заметим что в результате получили $$$3n$$$ вершин и $$$m + 7n$$$ ребер. При аккуратном написании MCMF вполне укладывается в TL.

Код

Div1E1+E2

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

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

Обозначим за $$$[l_i, r_i]$$$ отрезок, включающий все силы городов в группе $$$i$$$, где $$$r_i$$$ — максимальная сила города из этой группы, а $$$l_i$$$ — минимальная. При $$$l_i \le r_{i+2}$$$ невозможно построить контест, так как между городами соответствующим $$$l_i$$$ и $$$r_{i+2}$$$ должна быть разница хотя бы в 2 задачи, но они могут отличаться максимум на 1 задачу по специализации. После этого задача сводится к рассмотрению двух соседних групп и последующей проверки сложностей задач на соответствие линейным условиям каждой группы.

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

  • При $$$l_i \ge r_{i+1}$$$ для соблюдения порядка достаточно добавить несколько задач (а точнее всего 2) сложности из отрезка $$$[r_{i+1} + 1, l_i]$$$.

  • В противном случае каждый город $$$i$$$-й группы, лежащий в пересечении, должен решить задачу со своей специализацией. При этом ни одна задача не может быть в отрезке $$$[l_i + 1, r_{i+1}]$$$, так как город, имеющий наибольшую силу в группе $$$i+1$$$, решит не меньше задач, чем самый слабый город $$$i$$$-й группы, чего нам допускать нельзя. Для соблюдения порядка с остальными группами достаточно добавить 2 задачи сложности $$$r_{i+1} + 1$$$ (в отличие от первого случая, в силу того, что не может быть $$$l_i \le r_{i+2}$$$, здесь можно сразу определить подходящую сложность задач, но их можно будет расставить по тому же алгоритму, что и для 1-го случая).

Можно заметить, что при добавлении двоек задач им нужно выбирать не используемую никем спецификацию (так как мы ее в принципе не используем, но иначе это может породить коллизии).

Получаем, что нам необходимо расставить задачи с заданной спецификацией, которую сможет решить город из пересечения групп, то есть ее сложность должна быть не больше мудрости этого города, а так же расставить по 2 задачи некоторых сложностей для соблюдения порядка между группами. Эти трудности появляются из-за возможного пересечения с другими группами при использовании $$$r_{i+1} + 1$$$ как сложности задачи и возможных коллизий спецификаций городов, из-за чего город из слабой группы может решить задачу, которую мы для него не предполагали, тем самым нарушив условия строгости между группами.

Большая часть проблем не может возникнуть при $$$m=2$$$, поэтому сказанное выше уже является решением (без небольших доработок) простой версии задачи.

Сначала решим, как выбрать сложность для задач с определенной спецификацией. Для этого запретим использовать спецификацию задач, соответствующую городам, которые образуют 2-й случай (то есть из $$$i+1$$$-й группы), со сложностью $$$[l_i, b_j]$$$, где j — номер такого города. Также, как было указано, мы не можем иметь вне зависимости от типа задачу из отрезка $$$[l_i + 1, r_{i+1}]$$$. Для определения сложности достаточно ее выставить максимально возможной (равной мудрости) и затем постепенно снижать, пока не попадем в разрешенную сложность.

Чтобы разрешить проблему из первого случая, поставим барьеры по 2 задачи со сложностью, равной силе некоторого города везде, где это возможно.

Если для данной конфигурации существует ответ, то мы его таким образом гарантированно построим, использовав не более $$$3 \cdot n$$$ задач. После всех вычислений нужно проверить, удовлетворяет ли построенный нами контест условиям задачи, и вывести -1 в противном случае.

Код

Div1F1

Можно заметить, что если строка содержит правильное количество количество символов 'Y', 'D', 'X' и не имеет двух подряд идущих одинаковых символов, то её можно получить при помощи заданных операций.

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

Посмотрим на текущую строку. Не умаляя общности, пусть первый её символ равен 'Y'. Тогда в строке должна встречаться строка 'DX' и/или строка 'XD'. Это верно потому что для отсутствия 'DX' и 'XD' необходимо чтобы между любой парой символов не равных 'Y' находился хотя бы один символ 'Y'. Этого, в лучшем случае, можно добиться поставив 'Y' через каждый символ. Таким образом, символов не равных 'Y' при наличии $$$n-1$$$ 'Y' можно поставить не более $$$n$$$. Но $$$3n-1>n$$$ при $$$n>0$$$.

Получается, что строка имеет вид 'Y...ADXB...'.

Если A $$$\neq$$$ B, мы можем удалить символы 'Y', 'D', 'X' и ничего не сломаем.

Если A = B, то A = B = 'Y', так как A != 'D' и A != 'X'.

Тогда строка имеет вид 'Y...YDXY...', и мы можем удалить подстроку 'YDX' и останется все еще несломанная строка 'Y...Y...'.

Div1F2

Выделим из строки подотрезки, полностью состоящие из '?'. Для каждого обозначим его длину за $$$len_i$$$ и два соседних символа (стоящих слева и справа) за $$$l_i$$$, $$$r_i$$$. (Если правый и/или левый символ отстуствуют, возьмем их за '#', как символ, не совпадающий ни с каким из нас интересующих.

Выпишем тривиальные ограничения на количество доступных символов каждого вида на отрезке. Очевидно, что символов каждого вида не может быть больше, чем $$$\frac{len_i+1}{2}$$$: поставим по одному символу через каждый символ. Но если, например, слева у нас стоял символ 'Y', то количество позиций, где мы можем поместить 'Y' сокращается на $$$1$$$. Итого мы можем поставить не более $$$\frac{len+1-(l_i=b)-(r_i=b)}{2}$$$ символов типа b. Выпишем такие ограничения для каждого типа символов и обозначим их за $$$Y, D, X$$$ соответственно.

Оказывается, что мы можем расставить $$$y$$$ символов 'Y', $$$d$$$ символов 'D' и $$$x$$$ символов 'X', тогда и только тогда, когда $$$y+d+x=len_i$$$ и $$$0\leq y \leq Y, 0 \leq d \leq D, 0 \leq x \leq X$$$. Это можно доказать по индукции или проверить стрессом на небольших значениях. Отсюда заключаем, что чтобы мы имели возможность расставить $$$x, d, y$$$ символов каждого вида, надо чтобы выполнялись неравенства выше.

Из равенства $$$y+d+x=len_i$$$ выразим $$$d=len_i - (x+y)$$$.

Получаются три ограничения: $$$0\leq x \leq X, 0 \leq y \leq Y, 0 \leq len_i - (x+y) \leq D$$$. Первые два образуют прямоугольник, а третье отрезает от него два угла под углом $$$45$$$ градусов. А это выпуклый многоугольник.

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

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

Итоговая асимптотика $$$O(n)$$$ с некоторой констаной.

Код

Полный текст и комментарии »

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

Автор MrLolthe1st, история, 3 года назад, По-русски

Здравствуйте! Есть такая вот задачка: дан массив длины n <= 400, каждое число в массиве — степень вершины в графе. Необходимо по заданному массиву определить минимальный размер максимального паросочетания + построить граф, удовлетворяющий условиям массива, в котором максимальное паросочетание — искомое минимальное паросочетание. Заранее спасибо!

Полный текст и комментарии »

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

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

Добрый день, имеется такая задача: https://acmp.ru/index.asp?main=task&id_task=561 Очень интересно, как решать. Попробовал разные подходы, но никак не могу придумать как же всё-таки решить её верно? Думаю, 2к+ рейтинга люди заинтересуются :) Заранее благодарю.

Полный текст и комментарии »

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

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

1216E2 - Numerical Sequence (hard version)

Обозначим длину последовательности от 1 до $$$i$$$ как $$$L_{i}$$$, тогда $$$L_{i} = L_{i-1} + DigitSum(i)$$$, где $$$DigitSum(x)$$$ — функция, которая получает количество цифр в числе $$$x$$$. Мы знаем, что каждый раз $$$L_{i}$$$ растет на какое-то число $$$e = DigitSum(i)$$$, при чем это число меняется не так часто — только после того, как $$$i$$$ стало больше $$$9, 99, $$$ и т.д. В таком случае, если мы знаем длину последовательности, которая сейчас росла на $$$e = DigitSum(i)$$$, то как только $$$i$$$ станет больше 9, $$$e$$$ увеличится на 1, больше 99 — на 1, и так далее. В этих точках роста $$$e$$$ мы можем посчитать длину ряда, который у нас уже сейчас есть. Первой точкой в этом ряду будет 0. Далее мы можем воспользоваться формулой: $$$E_{i} = E_{i-1} + i\times{(10^{i} - 10^{i-1})}$$$. Такую таблицу до $$$R$$$ мы можем построить за $$$O(DigitSum(R))$$$ — такую табличку можно предподсчитать до начала обработки запросов, при чем $$$R$$$ будет не более $$$\sqrt{2k}$$$. Доказать это несложно — возьмем худший случай, в котором длина новой прицепляемой последовательности растёт ровно на 1 — в таком случае длина всей последовательности будет равной $$$\frac{n*(n-1)}{2}$$$, в нашем же случае — ситуация будет лучше. Обозначим предподсчитанную последовательность как $$$P$$$. По $$$P$$$ мы можем построить вторую последовательность $$$O$$$, где $$$O_{i}$$$ будет обозначать длину цельной последовательности (той, что 1121231234..), после которой мы будем прицеплять новую последовательность от $$$1$$$ до $$$K$$$, где $$$K = 10^{i}$$$. Первым элементом будет $$$0$$$, для каждого следующего несложно вывести формулу $$$cnt = (10^{i}-10^{i-1}), O_{i}=O_{i-1}+P_{i-1}*cnt+i*\frac{cnt*(cnt+1)}{2}$$$. По данной последовательности $$$O$$$ и заданному $$$k$$$ несложно определить, сколько цифр будет содержать каждый последний элемент прицепляемой к нашей последовательности — $$$O_{i}\leq{k}<{O_{i+1}}$$$. Зная начало первой последовательности, у которой последний элемент будет равен $$$10^{i}$$$ (это и есть $$$O_{i}$$$) мы можем вычислить смещение нашей последовательности относительно $$$O_{i}$$$. Все последовательности до $$$O_{i+1}$$$, начинающиеся после/в $$$O_{i}$$$ будут начинаться относительно $$$O_{i}$$$ в индексах $$$e\times{P_{i-1}}+i\times{\frac{e*(e+1)}{2}}$$$, где $$$e$$$ — номер последовательности. Таким образом, мы можем решить квадратное уравнение $$$e\times{P_{i-1}}+i\times{\frac{e*(e+1)}{2}}=absK$$$, где $$$absK=k-O_{i}$$$. Домножив всё на два мы получаем уравнение $$$2\times{e\times{P_{i-1}}}+i\times{e^{2}}+i\times{e}=2\times{absK} \Leftrightarrow i\times{e^{2}}+(2\times{P_{i-1}}+i)*e-2\times{absK}=0$$$. Таким образом, коэффициенты соответственно равны $$$a=i, b=2\times{P_{i-1}}+i, c=-2\times{absK}$$$. Решив его, берем корень $$$x_{1}=\frac{\sqrt{d}-b}{2a}$$$. Теперь, мы знаем сколько последовательностей началось до нас, значит, мы знаем и наш индекс в текущей последовательности — $$$curr = absK - (P_{i-1}*a_{1}+i\times\frac{a_1\times{(a_1+1)}}{2})$$$. Далее — мы можем определить, в диапазон каких чисел мы попали(по количеству цифр) — нам в этом поможет $$$P$$$ — тогда $$$P_j\leq{k}<P_{j+1}$$$, вычтя из $$$k$$$ $$$P_j$$$ мы получим число $$$u$$$, которое показывает в какую цифру среди записи чисел $$$10^i, 10^i+1, ..$$$ нам надо "тыкнуть". Таким образом, число, стоящее на месте, где находится $$$cur$$$ — это $$$10^i+(u-1)\div{j}$$$, а сама цифра в этом числе — $$$(u-1)\mod{j}$$$. если $$$u<10$$$, то следует вывести просто $$$u$$$, во избежания разбора дополнительных вариантов.

Решение — 61064504

Полный текст и комментарии »

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