Вы находитесь на странице: 1из 102

*

© 2016, А.А. Афанасенко, Э.О. Гамисония,


А.Э. Турчинович, С.А. Коноплич
*

Количество решений 41
Количество полных решений 9
Среднее количество баллов 48,78
*
Объявим двумерный массив целых чисел Field которой будем заполнять
как

Также объявим переменную n - количество «живых» клеток всех


кораблей на поле и массив ost. ost[i] - количество «живых» клеток i-го
корабля на поле.
Field можно заполнить таким образом:
• Изначально всем клеткам поставим 0
• Последовательно идем по исходному массиву символов, если
встречаем символ корабля, то проверяем Field у соседних
клеток(лево, право, верх, низ) если он равен 0 у всех соседних, то
присвоим текущей клетке новый номер корабля, если у кого-то из
соседей он не равен 0, то присвоим текущей клетке ненулевой
номер соседней клетки. Заполняем попутно ost и n
*
При обработке запросов у нас есть координаты x, y. При этом y
представляет собой символ и его необходимо преобразовать в число, для
того что использовать его в массиве Field как индекс. Проще всего это
сделать отняв от y код символа ‘a’, но необходимо учитывать что в задаче
пропущена буква ‘i’ поэтому нужно дополнительное условие.
Обработка запросов:
1. Если Field[x][y] = 0, то выводим MISS, т.к. наша клетка либо пуста,
либо содержит подбитую часть корабля.
2. Если 1 ≤ Field[x][y] ≤ 10, то уменьшаем n на 1 (количество всех
«живых» клеток кораблей на поле), уменьшаем ost[Field[x][y]] на 1
(количество «живых» клеток корабля) после проверяем:
1. Если n = 0, то выводим GAME OVER, т.к. Все корабли уничтожены.
После вывода GAME OVER, нужно остановить обработку запросов
2. Если ost[Field[x][y]] = 0, то выводим DEAD
3. В ином случае выводим HIT
После помечаем клетку как подбитую, Field[x][y] := 0
*

Количество решений 31
Количество полных решений 0
Среднее количество баллов 25,5645
• Дано K, Y
• Найти K различных чисел
• 𝑋1 𝑎𝑛𝑑 𝑋2 𝑎𝑛𝑑 … 𝑎𝑛𝑑 𝑋𝑘 = 𝑌
• 𝑋𝑖 < 230

• Если так нельзя, вывести “−1”


• Всегда выводим “−1”
• Если K=1, выводим Y
• Если K=1, выводим Y
• Иначе выводим “−1”
110000
AND 1 0 1 1 0 0
101010
100000
• 𝐾 ≤3
• 𝑌 ≤1
• K = 1 или 2 или 3
• Y = 0 или 1
if для каждого
случая ;)
• Если Y = 0, то ответом
будет 0 и любые другие
числа.
• Если 𝑌 = 1, то ответом
будет
110 = 0012 ,310 = 0112 ,710 =
1112
000111
AND 0 0 0 0 1 1
000001
000001
• 𝐾 ≤3
• 𝑌 ≤ 1000 < 𝟐 𝟏𝟎
• Возьмем 𝑋1 = 𝑌
• Затем, если нужно еще одно
число, возьмем 211 − 1. Это
число состоит из 11 единиц.
• Такое число не портит AND. И
оно отлично от Y.
• И если нужно еще одно число,
возьмем 212 − 1. Это число состоит
из 12 единиц.
• Такое число не портит AND. И оно
отлично от Y и от 211 − 1.
Таким образом, ответом будет
• 𝑋1 = 𝑌
• 𝑋2 = 2 11
−1
• 𝑋3 = 212 − 1
• Если в каком-то из битов
числа Y есть 1
• То в каждом 𝑋𝑖 этот бит
будет равен 1
? ?1? ?1
AND ? ? 1 ? ? 1
? ?1? ?1
001001
• Пусть 𝐶 – количество
единичных битов в числе Y.
• Тогда 30 − 𝐶 количество
битов в числе 𝑋𝑖 , которые
не определены
однозначно.
? ?1? ?1
AND ? ? 1 ? ? 1
? ?1? ?1
001001
• Всего вариантов чисел 230−𝐶
• Если 𝐾 > 230−𝐶 , то ответа не
существует гарантировано.
• Пусть 𝑋1 = 𝑌
? ?1? ?1
AND ? ? 1 ? ? 1
001001
001001
• Теперь можно составить
различные числа, заполняя
неизвестные позиции.
001101
AND 0 0 1 0 1 1
001001
001001
• Запомним позиции битов
числа Y, которые равны 0.
• Все позиции от 0 до 29
• Затем рекурсивно построим
все числа.
• Запустим рекурсию от
числа Y и первого 0-бита.
• На каждом шаге продолжим:
rec(x, nextBitPos);
𝑐𝑢𝑟𝐵𝑖𝑡𝑃𝑜𝑠
rec(x + 2 ,nextBitPos);
• Где x – текущее число
• curBitPos – текущая позиция 0-
бита
• nextBitPos – следующая
позиция 0-бита
• После того, как мы просмотрели
все позиции 0-битов, закончим
рекурсию.
• Полученное число добавим в
список ответов.
• Очень важно, чтобы число Y
попало в ответ.
• Случай K = 1(первые два теста)
• Выводим K сформированных
чисел.
• И получаем 100 баллов!
*

Количество решений 28
Количество полных решений 0
Среднее количество баллов 20.36
*
Задача решается методом динамического программирования.

Пусть 𝑎- входная последовательность, 𝑐𝑜𝑢𝑛𝑡𝑖


задаёт, сколько раз в последовательности
встречалось число 𝑖, а 𝑙𝑒𝑓𝑡𝑖 и 𝑟𝑖𝑔ℎ𝑡𝑖 - это
индексы крайнего левого и крайнего правого
вхождения числа 𝑖 в последовательности 𝑎
соответственно. Отсортируем эти массивы
по возрастанию 𝑙𝑒𝑓𝑡𝑖 , так, чтобы
последовательности одинаковых чисел шли
слева направо.
*
Рассмотрим число 𝑗 ∈ [1, 𝑖 − 1], 𝑙𝑒𝑓𝑡𝑗 < 𝑙𝑒𝑓𝑡𝑖 ,
т.к. числа отсортированы по возрастанию
значения 𝑙𝑒𝑓𝑡𝑖 . Если в то же время
𝑟𝑖𝑔ℎ𝑡𝑗 > 𝑟𝑖𝑔ℎ𝑡𝑖
то мы не можем использовать в интересной
последовательности одновременно числа 𝑖 и
𝑗, т.к. получится, что в таком случае одно из
чисел 𝑖 будет находиться где-то между
числами 𝑗, следовательно,
последовательность не будет являться
интересной.
*
Тогда 𝑓𝑖 - максимальная длина интересной
последовательности, заканчивающейся числом 𝑖.
𝑓𝑖 = max(𝑓𝑗 + 𝑐𝑜𝑢𝑛𝑡𝑖 )
где
𝑗 ∈ 1, 𝑖 − 1 и 𝑟𝑖𝑔ℎ𝑡𝑗 < 𝑟𝑖𝑔ℎ𝑡𝑖
либо 𝑓𝑖 = 𝑐𝑜𝑢𝑛𝑡𝑖 , если таких чисел 𝑗 не найдено.
Ответом будет являться max 𝑓𝑖 , 𝑖 ∈ [1, 𝑛].
Время работы алгоритма 𝑂(𝑛 + 𝑘 2 ), где k –
максимально возможное число в
последовательности 𝑎.
*

Количество решений 29
Количество полных решений 0
Среднее количество баллов 9,66
Краткое условие
Дан диск из N (1 ≤ N ≤ 2000) поясов.
Каждый пояс разделён на K (1 ≤ K ≤ 2000) секторов,
покрашенных в один из K цветов.
Пояса могут вращаться независимо друг от друга.
Поворот на 1 сегмент занимает 1 секунду.

Задача: Привести за минимальное время диск в такое


состояние, что найдётся хотя бы один радиус
пересекающий N секторов одного цвета.
Иллюстрация из условия
На картинке видно, как
сдвинув средний пояс два
раза можно получить
сектор диска из трёх
единиц
Формализованное условие
Дана целочисленная матрица A(N x K), где
1 ≤ A[i,j] ≤ K.
Разрешено циклически сдвигать строки
матрицы в любую сторону.
Сдвиг на Х позиций имеет стоимость Х.

Задача: За минимальную стоимость собрать


хотя бы один столбец из одинаковых чисел.
Частичные решения
30 баллов (N ≤ 2, K ≤ 100):
Перебираем цвет и сектор диска, который будет
закрашен в один цвет. Также перебираем
всевозможные повороты дисков (за сложность
K^N), дающие сектор текущего цвета. Выбираем
ответ с минимальной стоимостью.

Итоговая сложность О(K^N*N*K).


Частичные решения
40 баллов(N, K ≤ 100):
Перебираем цвет и сектор (за сложность K^2),
проходим по всем поясам и ищем ближайший
сектор подходящего цвета (за сложность K*N).

Итоговая сложность О(K^2*N*K).


Частичные решения
60 баллов (N, К ≤ 300):
Предпосчитаем для каждого цвета на каждом
поясе и секторе расстояние до ближайшего
сектора этого цвета.
Перебираем цвет и сектор (K^2), проходим по
поясам и для расчёта ответа используем заранее
вычисленные значения.
Итоговая сложность О(N*K^2)
Частичные решение
80 баллов (N, K ≤ 1000):
Решается динамическим программированием с
применением дерева отрезков. Оптимизированный
вариант легко берёт эту планку, но на следующей
группе время работы немного превышает
поставленную авторами планку в 5 секунд.
Начинаются серьёзные дела
Полное решение
Для упрощения работы со сдвигами
продублируем матрицу. Очевидно, что
подотрезок любой строки длины K будет являться
одним из циклических сдвигов этой строки, а
множество всевозможных подотрезков длины K
будет являться множеством всевозможных
циклических сдвигов строки.
Таким образом мы избавляемся от проблемы,
когда ближайший цвет находится на
противоположной стороне строки матрицы.
Полное решение
1 2 3 1 2 3 1 2 3

3 1 2 3 1 2 3 1 2

2 3 1 2 3 1 2 3 1

1 2 3 4 5 1 2 3 4 5 1 2 3 4 5

4 5 1 2 3
Подготовка к решению
Создадим K списков Pos, в i-том списке
будут храниться координаты всех ячеек
цвета i в продублированной матрице.
Переберём цвет, который будем собирать.
Пусть Clr — текущий цвет.
С помощью списка посчитаем ответ для
столбца с номером 1 (т.е. собираем цвет Clr
в первом столбце и считаем стоимость).
Сразу проверим возможность собрать
столбец, ведь в какой либо строке может и
не быть ячеек цвета Clr.
Ближе к сути
Продолжаем перебирать цвет. Заведём для
каждого столбца S — список позиций. Смысл
этих позиций станет ясным далее.
Добавим в список S первую координату из
списка позиций Pos[Clr].
Теперь переберём ячейки из Pos[Clr]
начиная со второй. Пусть текущая ячейка
имеет индекс i в этом списке, а запись
S[x].add(y) будет означать добавление
ячейки y в список S[x].
Приготовьтесь, немного кода
Будем добавлять ячейку в столбец, в
котором она находится, а так же в среднюю
(медианную) ячейку между прошлой
координатой и текущей.
Первые ячейки в строке добавляются без
медиан.
Немного кода
S[Pos[Clr][i].y].add(Pos[Clr][i].x, Pos[Clr][i].y)
(добавляем координату клетки с нужным цветом
в список, который хранит все клетки этого цвета,
которые находятся в столбце Pos[Clr][i].y)
M = (Pos[Clr][i].y + Pos[Clr][i - 1].y + 1) div 2
(вычисляем медиану между предыдущей
координатой из списка и текущей)
S[M].add(Pos[Clr][i].x, Pos[Clr][i].y)
(добавляем Pos[Clr][i].x, Pos[Clr][i].y в столбец M,
как будто клетка с такой координатой находится
там. Зачем? Об этом следующий слайд)
Но зачем?
Что мы имеем к данному моменту?
Любая медиана или ячейка цвета Clr
является так называемым экстремумом.
Пусть на i+1 позиции мы ближе к нужной
ячейке, тогда после её достижения мы
начинаем отдаляться, пока не достигнем
медианы. Тогда расстояние до ближайшей
подходящей ячейки начнёт уменьшаться.
Кружки

Плюс означает, что при движении вправо мы


приблизимся к ответу, минус означает
обратное.
Решение
Давайте считать ответ для каждого столбца
и выбирать минимальный.
Для подсчёта ответа давайте заведём
массив L длинной N, характеризующий
приближение или отдаление от требуемой
ячейки для строки i. Единица будет означать
приближение к цели, а ноль, соответственно,
отдаление.
Решение
Допустим в массиве L хранится T единиц,
тогда ответом для нового столбца является
ans = oldAns + n - 2*T
Сравниваем ответ с минимальным и
продолжаем.
Пройдём по списку экстремумов и изменим
знаки массива L в нужных строках.
Этот подход называется Методом Событий.
Вопросики?
*

Количество решений 42
Количество полных решений 9
Среднее количество баллов 47.80
*
Можно перебирать все дни года, проверяя
какой это день месяца и день недели, и, в
случае совпадения с днем недели и днем
месяца празднования Дня Святого Байта,
увеличивать счетчик на 1.
Время работы алгоритма 𝑂(𝑀 ∗ 𝐾), где
𝐾 = max(𝐷𝑖 ).
Набирает не менее 80 баллов.
*
Для полного решения достаточно заметить,
что перебирать все дни года не требуется,
достаточно для каждого месяца проверить,
является ли дата с выбранным месяцем и
днем месяца t, днем недели празднования
Дня Святого Байта.
*
Чтобы по выбранному месяцу 𝑀𝑖 и дню месяца t
определить день года 𝑑, 𝑑 = 𝑆𝑢𝑚 𝑀𝑗 + 𝑡, j < i.
День недели равен числу 𝑏, если выполняется
условие 𝑏 = 𝑑 − 𝑠 % 𝑊 + 1, где оператор % -
остаток по модулю.

Примечание: 𝑆𝑢𝑚 𝑀𝑗 каждый раз заново


вычислять не требуется, достаточно к
предыдущему посчитанному значению 𝑆𝑢𝑚 𝑀𝑗−1
найти текущее: 𝑆𝑢𝑚 𝑀𝑗 = 𝑆𝑢𝑚 𝑀𝑗−1 + 𝑀𝑗 .
*

Количество решений 40
Количество полных решений 1
Среднее количество баллов 16,38
Формализованное условие
Даны массивы H и B из N ≤ K ≤ 3000
элементов.
Выбрать такую подпоследовательность
P из H длиной N, что выполняются условия
P[i]<P[i+1] и H[i]+B[P[i]] < H[i+1]+B[P[i+1]]
Решение
Решается динамическим
программированием, за сложность O(N*K),
решение без оптимизации работает за
сложность О(N*K*K), что берёт планку в 80
баллов.
Вопросы?
*

Количество решений 33
Количество полных решений 0
Среднее количество баллов 8.33
• N – домов
• N – писем
• K – количество проходов по улице
• A – массив расположения домов
• Письма расположены в порядке
возрастания адресата
• Дома в произвольном порядке
• Отдать письмо можно только с
вершины стопки писем
• Письмо можно пропустить
• Пропущенное письмо доставлено
быть не может
• Максимизировать кол-во писем
• Выводить всегда одно и то же
число в надежде, что мы
угадаем ответ одного из тестов
• 𝐾=1
• 𝑁 ≤ 1000
• Найти наидлиннейшую
возрастающую
подпоследовательность
13524
• 2
Динамика за 𝑂(𝑁 )
• Пусть 𝐷𝑖 , длина НВП которая
заканчивается в элементе i.
• 𝐷𝑖 = 1
• Для каждого элемента
последовательно будем
просматривать все предыдущие
элементы.
• Если элемент меньше
рассматриваемого, попробуем
улучшить 𝐷𝑖
• 𝐷𝑖 = max(𝐷𝑗 + 1, 𝐷𝑖 ).
• 𝐾 ≤ 10
• 𝑁 ≤ 10000
• Построим массив 𝐵, в который
будем добавлять 𝐾 раз массив 𝐴
или перевернутый массив 𝐴.
N=7 K=3
A=1 7 2 6 3 5 4
Тогда
B=
1726354+
4536271+
1726354
B=172635445362711726
354
• Найдем в этом массиве
наидлиннейшую возрастающую
подпоследовательность
за 𝑂(𝑁𝐾 log(𝑁𝐾))
• Пусть 𝐷𝑖 элемент массива,
которым заканчивается
возрастающая
подпоследовательность длины i.
• Если таких элементов несколько
то наименьший
• Такую динамику можно строить
последовательно с 𝐴1 до 𝐴𝑛
• Для текущего элемента 𝐴𝑖
• Рассмотрим все 𝐷𝑗 .
• Если 𝐷𝑗−1 < 𝐴𝑖 и 𝐴𝑖 < 𝐷𝑗 . То мы
можем улучшить ответ для 𝐷𝑗 .
• Просмотрев все элементы,
выведем максимальное j, такое
что 𝐷𝑗 было улучшено хотя бы
раз.
• Для этого по умолчанию
• 𝐷0 = −∞, 𝐷𝑖 = ∞, 1 ≤ 𝑖 ≤ 𝑁
• 𝐷𝑖−1 < 𝐷𝑖 , 0 ≤ 𝑖 ≤ 𝑁
• Каждый 𝐴𝑖 обновляет максимум
одну ячейку.
• Так как 𝐷𝑖 возрастает
• Можно воспользоваться
бинарным поиском и искать
сразу возможный 𝐷𝑖 для
обновления.
• Необходимо найти первое 𝐷𝑗 ,
которое больше 𝐴𝑖
• Найденному 𝐷𝑗 , присвоить 𝐴𝑖
• В итоге получим
• Время: 𝑂 𝑁𝐾 log 𝑁𝐾
• Память: 𝑂(𝑁𝐾)
• И 60 баллов
• Заметим что длина НВП всегда
будет ≤ 𝑁
• Поэтому достаточно строить
динамику от 0 до N.
• Хранить массив B
необязательно.
• В итоге получим
• Время: 𝑂 𝑁𝐾 log 𝑁
• Память: 𝑂(𝑁)
• Результат: 100 баллов
*

Количество решений 38
Количество полных решений 0
Среднее количество баллов 49.59
Необходимо расставить книги N авторов,
на матрице размером NxN так, чтобы
максимум из количеств различных авторов
в рядах, был минимальным.
A[i] - количество книг i-го автора, при
этом
N итераций, на каждой из которых нам нужно найти
автора x такого, что A[x] ≤ N, и автора y такого, что
A[y] ≥ N. Такие авторы обязательно будут
существовать.
Сначала следует разместить в i-том ряду все книги
автора x, затем до конца ряда разместить книги
автора y. После автора x нужно из поиска убрать, а
автору y, изменить A[y] значение на A[y] := A[y] –
(N – A[x]).
Отдельно можно обработать случай, когда x = y
Почему x, y будут существовать на каждой
итерации?
Для 1ой итерации: книг N^2; N авторов; среднее
(N^2)/N = N.
Для 2ой итерации: книг N^2 – N; N-1 авторов, и
среднее (N^2-N)/(N-1) = N и т.д. Таким образом,
среднее значение равно N на всех итерациях.
Доказательство можно вывести по индукции.
Есть множество вариантов для поиска x, y в том
числе тесты позволяли делать это и за линию.
Таким образом, максимум из минимумов
различных авторов в ряду всегда будет
равен 1 или 2.
Реализовать это решение можно разными
способами. Значение N в тестах не
превосходило 1000, поэтому можно было
использовать решение, работающее и за
O(n2), хотя существуют и более быстрые
реализации.
Спасибо за внимание!