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

Автор AlexFetisov, история, 9 лет назад, перевод, По-русски

Задача A (div2):

Очевидно, что нам необходимо делать последовательность ходов вида: 1, 2, 1, 2, ...

Ответ будет примерно равен 2 * n / 3. После этого у нас останется 0, 1 или 2 камня. Если у нас осталось 0 камней, то все закончилось, иначе у нас осталось либо 1, либо 2 камня и очевидно, что мы можем в этих случаях взять только 1 камень.

Итоговый ответ: 2 * n / 3 + (n % 3 != 0 ? 1 : 0);

Задача B (div2):

Мы можем просто симулировать поведение кузнечика и отмечать все позиции, на которых он был. Очевидно, что таких различных позиций будет O(n). Если кузнечик попадет на клетку, где он уже был, то мы попали в цикл, и ответ — INFINITE. Иначе — FINITE.

Задача A(div1)/C(div2):

Давайте заведем 2 матрицы: a, idx. В матрице a мы будем хранить NULL для ячеек, о которых мы ничего не знаем или значение, если мы уже его определили. idx будет инициализировано как idx[i][j] = {i, j}; Затем просто просимулируем процесс для матрицы idx. Для запросов 3-его типа мы можем просто присвоить значение в матрице a, так как мы знаем исходную позицию по матрице idx.

Задача B(div1)/D(div2):

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

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

Задача C(div1)

Сперва решим обратную задачу: найдем минимум (максимум) от двух распределений. Воспользуемся формулами:

P(a = k) = P(a <= k) — P(a <= k-1) P(max(a, b) <= k) = P(a <= k) * P(b <= k)

Соответственно для минимума:

P(min(a, b) >= k) = P(a >= k) * P(b >= k) = (1 — P(a <= k-1)) *(1 — P(b <= k-1))

Теперь в наших формулах из условия минимум и максимум определяют систему квадратных уравнений для каждой пары P(a <= k), P(b <= k).

Если решить эти уравнения, мы получим P(a<=k), P(b<=k) = (u + v ± sqrt((u + v)^2 — 4u)) / 2, где u = P(max(a,b) <= k), v = P(min(a,b) <= k). Теперь можно заметить, что если ответ существует, то мы тогда существует ответ, когда мы выберем знаки для каждой пары одинаково. (смотри комментарий)

Задача D(div1)/E(div2):

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

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

Задача E(div1):

Построим для обеих формул граф импликаций и найдем компоненты сильной связности в графе. Если обе формулы несовместны, то ответ SIMILAR. Если только одна формула несовместна, то ответ — ответ для второй формулы.

Допустим обе формулы совместны. Построим транзитивное замыкание для графов. Будем называть переменную X фиксированной в формуле F, если существует путь из -> x или (x -> ). Если есть фикированная переменная в одной формуле, но не в другой (или фиксированная, но имеет другое значение) мы можем найти ответ для второй формулы с противоположным значение этой переменной — это и будет ответом. Если мы не смогли найти эти переменные — удалим их все. В оставшемся графе нет фиксированных переменных. Найдем такое ребро u->v, которе есть в одном графе, но отсутствует в другом. Найдем решение для формулы без этого ребра, когда u = 1 и v = 0 (мы всегда можем найти решение). Это и будет ответ.

Задача F(div1):

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

1) (разбиение k+1 вершин) x (разбиение k+1 вершин) -> (разбиение k+1 вершин | null), переводящее пару разбиений — лесов в набор компонент связности их объединения, или null если появится цикл

2) (разбиение k+1 вершин) x (вершина) -> (разбиение k+1 вершин | null), переводящее лес в новый лес, образованный добавлением ребра из вершины в вершину k+1 (или null, если образуется цикл)

3) (разбиение k+1 вершин) -> (разбиение k вершин | null), проецирующее разбиение на первые k вершин (или null, если k+1-ая вершина образовывает отдельную компоненту)

Детали реализации можно посмотреть в решении автора.

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

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

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

Всего через 6 с половиной часов начнётся Раунд 2 чемпионата по программированию VK Cup 2016! Если вы не зарегистрировались на раунд — не беда! Есть дополнительная регистрация!

В этом раунде могут принять участие все те команды, которые отобрались в Раунде 1 или в Уайлд-кард раунде 1. Участников ждет соревнование по правилам классических раундов Codeforces. Одновременно с основным раундом будет проведена интернет-трансляция, которая представляет из себя обычный рейтинговый div1/div2-раунд по правилам Codeforces. В трансляции может участвовать любой участник, не зарегистрированный на основной раунд в составе отобравшейся команды.

Раунд для вас подготовили AlexFetisov и winger. Это первый для нас раунд на Codeforces в качестве авторов. Огромное спасибо Глебу Евстропову (GlebsHP) за долгое сотруднечество и помощь в приготовлении раунда. Глеб делает колоссальную работу, и я хотел бы это отметить еще один раз! Также большое спасибо Kamil Debowski (Errichto), Mateusz Radecki (Radewoosh), Боре Минаеву (qwerty787788), Паше Кунявскому (PavelKunyavskiy) за прорешивание задач и дельные советы. Огромное спасибо Мише Мирзаянову (MikeMirzayanov) за все, что он сделал для всех нас!

Напомним, что в Раунд 3 пройдут все те команды, которые наберут положительный балл, не меньший, чем у команды на 100-м месте. Также обращаем ваше внимание, что все команды, проходящие в Раунд 3, получат фирменную футболку Чемпионата. Помимо этого, фирменной футболкой будут награждены топ-50 участников интернет-трансляции Раунда 3.

Желаем удачи и интересной борьбы!

Обновление

Раунд завершен. Надеюсь, задачи вам понравились! Поздравляем победителей!

Официальный VK Round 2:

  1. Who`s On First Base!: -XraY-, ershov.stanislav
  2. Beer and lemon tea: sankear, Zlobober
  3. MYCOPOBO3: V--o_o--V, LHiC
  4. Never Lucky: subscriber, tourist
  5. 33% less bad jokes: ifsmirnov, Arterm

Результаты Div1:

  1. anta
  2. jqdai0815
  3. Petr
  4. dotorya
  5. ikatanic

Результаты Div2:

  1. alexrcoleman
  2. nherceg
  3. santjuan
  4. mkisic
  5. unused

Разбор

http://codeforces.me/blog/entry/44538

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

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

Автор AlexFetisov, 14 лет назад, По-русски
Добрый день) Решая ГП Европы, придумал задачу В (там где надо сориентировать ребра так, чтобы граф стал Эйлеровым), но написать уже не успевал) Потом прочитал на СФ разбор Ильи Корнакова и тихо порадовался, что знаю как решать такие задачи. Однако на пути из Питера решил написать ее в поезде и получил ВА 5. Искал баг и ничего не нашел, так и не знаю, где косяк. Вот и подумал, может кто подскажет. По шагам то, что я делаю.
1) Ищу минимальный возможный вес ребра и максимально возможный, где минимальный - это максимум из минимумов весов по каждому ребру, а максимальный - максимум всех весов.
2) Бин поиском подбираю вес
3) Строю граф по ребрам у которых вес >= текущему
4) Проверяю граф на достижимость из вершины 0.
5) Для каждой вершины читаю ее полустепень входа и выхода, потом беру минимум из этих двух величин и вычитаю из каждой этот минимум (то есть свожу одну из них в ноль)
6) Добавляю ребра из истока в каждую вершину с положительной полустепенью входа с пропускной способностью, равной этой степени, и в сток добавляю ребра из вершин с положительной полустепенью выхода, с пропускной способностью, равной этой степени.Остальные ребра добавляю в сеть такие как есть с пропускной способностью 1
7) Нахожу макс поток
8) Перебираю ребра в сети, которые не ведут из истока и в сток. Если поток по ребру положительный, то ориентирую это ребро в сторону потока.
9) Строю граф на неориентированных ребрах
10) Проверяю степень каждой вершины этого графа на четность
11) Нахожу для каждой компоненты связности Эйлеров цикл и ориентирую ребра вдоль него.
12) Строю исходный граф с найденной ориентацией ребер и нахожу Эйлеров цикл.
Может где то в логике косяк? В коде не нахожу.

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

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