Привет, Codeforces!
В этом посте я бы хотел рассказать про решение двух типов задач, с почти одинаковым решением. К сожалению я не знаю, насколько эта идея распространена. Впервые я ее придумал на региональном этапе 2021/22 года по информатике для определенной подгруппы. А на днях заметил в задаче с Google Kick Start и 1637E - Лучшая пара, поэтому решил написать данный пост.
Задача 1
Формулировка: Дано число $$$0 \leq K < 10^5$$$ и два отсортированных по возрастанию массива $$$a_1, a_2, \ldots, a_n \ (a_i \leq 10^9)$$$ и $$$b_1, b_2, \ldots, b_n \ (b_i \leq 10^9)$$$. Были выписаны $$$n^2$$$ дробей вида $$$\frac{a_i}{b_j}, 1 \leq i \leq n, 1 \leq j \leq n$$$. После этого все эти дроби были отсортированы по возрастанию. Нужно вывести значение K-ой по возрастанию дроби.
Идея: Казалось бы, генерируется $$$n^2 \leq 10^{10}$$$ чисел, и нельзя получить отсортированный массив за разумное время. Однако, если посмотреть на ограничение по $$$K$$$ можно понять, что нас интересуют не все $$$n^2$$$ чисел, а только $$$K$$$ наименьших. Тогда давайте поддерживать минимальное число и из него переходить в следующее.
Решение: Для удобства развернем массив $$$b$$$, чтобы он стал отсортирован по убыванию и обозначим за $$$(i, j)$$$ дробь $$$\frac{a_i}{b_j}$$$. Несложно заметить, что $$$(i, j) \leq (i + 1, j)$$$ и $$$(i, j) \leq (i, j + 1)$$$. Отсюда ясно, что $$$(0, 0)$$$ будет первым элементом в отсортированном массиве. Утверждение заключается в том, что если мы рассмотрели $$$(i, j)$$$ как минимальную дробь, то в "кандидаты" на новый минимум добавляется две дроби $$$(i + 1, j)$$$ и $$$(i, j + 1)$$$. Это кажется интуитивно понятным, однако чуть ниже попытка доказать, почему это так. Задача свелась к тому, чтобы поддерживать кандидатов и брать лучшего из них.
Задача 2
Формулировка: 1637E - Лучшая пара
Идея: Заметим, что различных $$$cnt_x$$$ не более $$$\sqrt{n}$$$. Создадим массив $$$A$$$, который в индексе $$$i$$$ хранит отсортированный по убыванию вектор $$$x$$$ таких, что $$$cnt_x = i$$$. Тогда переберем $$$cnt_x, cnt_y$$$. Так как один из множителей мы зафиксировали, нам нужно максимизировать $$$x+y$$$.
Для удобства обозначим $$$a = A[cnt_x]$$$, $$$b = A[cnt_y]$$$. Позицией будем называть $$$(i, j)$$$. Нужно выбрать такую позицию, что $$$(a_i, b_j)$$$ не является запрещенной парой. Используя наблюдения, которые были высказаны выше, замечаем, что:
- Лучший ответ в "позиции" $$$(0, 0)$$$
- Если нас не устраивает $$$(i, j)$$$ мы переходим в $$$(i + 1, j)$$$ или $$$(i, j + 1)$$$
Это та же задача 1, но теперь мы делаем не фиксированное количество раз, а пока лучшая пара является запрещенной. Мое решение на это задачу: 146149856
Задача 3
Формулировка: Вам поступило $$$N$$$ заказов напитков от друзей. Напиток задается битовой строкой $$$s_i$$$ длины $$$P$$$. Если вы купите напиток $$$S$$$ то $$$i-ый$$$ друг будет недоволен столько раз, сколько существует индексов $$$j$$$, что $$$S_j \neq s_{i, j}$$$. Однако по экономическим соображениям в магазин, в котором вы покупаете напиток, есть $$$M$$$ напитков, которые купить нельзя.
Дано: $$$1 \leq N \leq 100, 1 \leq P \leq 100, 0 \leq M \leq min(100, 2^P - 1)$$$. Вам нужно выбрать такую строку $$$S$$$, что суммарное недовольство всех друзей будет минимальным.
Идея: Аналогично задаче 2 у нас есть запрещенные множества и среди остальных нужно выбрать лучшее (в данном случае функция от множества это количество недовольств). Начальное значение определить не сложно: для каждого бита независимо смотрим, выгоднее поставить 0 или 1. Далее мы пытаемся изменить ровно один бит. Логика такая же, как и в задаче 2, но теперь не 2 перехода, а $$$P$$$. Сложность $$$O(PMlog(PM))$$$.
Надеюсь данная идея поможет кому-то в решении задач.