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

Подготовка к областной олимпиаде

Марафон - 2022

Задача F. Нам нужны массивы!


Ограничение по времени: 1 секунда
Ограничение по памяти: 64 мегабайта

Нам нужны массивы, которые обладают следующими свойствами:

∙ количество элементов в массиве − натуральное число;


∙ сумма всех элементов равна 𝑠, число 𝑠 задано;

∙ 𝑎1 = 𝑘, число 𝑘 задано;
∙ любые два соседних элемента различны: 𝑎𝑖 ̸= 𝑎𝑖+1 ;
∙ если 𝑎𝑖 < 𝑎𝑖+1 , то 𝑎𝑖+1 > 𝑎𝑖+2 ;
∙ если 𝑎𝑖 > 𝑎𝑖+1 , то 𝑎𝑖+1 < 𝑎𝑖+2 ;

Требуется написать программу, которая по заданным 𝑠 и 𝑘 определяет, сколько различных массивов


удовлетворяют описанным требованиям, и выводит остаток от деления количества таких массивов на число
109 + 7.

Формат входных данных


Во входных данных находятся целые числа 𝑠 и 𝑘 (1 6 𝑠 6 5 000, 1 6 𝑘 6 𝑠).

Формат выходных данных


Выведите одно число: остаток от деления количества массивов на 109 + 7.

Примеры
тест ответ
6 2 4
3 3 1

Пояснения к примерам
В первом примере подходят следующие массивы: [2, 1, 2, 1], [2, 1, 3], [2, 3, 1], [2, 4]. Во втором примере един-
ственный подходящий массив [3].

Страница 12 из 34
Подготовка к областной олимпиаде
Марафон - 2022

Разбор задачи «Нам нужны массивы!»


Решение.

Для небольших значений 𝑠 можно применить рекурсивный перебор вариантов. При использовании акку-
ратного перебора с отсечениями можно решать задачу при 𝑠 ∼ 30. Если для 𝑠 порядка 30 перебор не успевает
найти ответ за отведенное ограничение по времени, можно применить метод предподсчёта: заранее на своём
компьютере найти ответы для всех тестов с 1 6 𝑘 6 𝑠 6 30 и отправить на проверку программу, которая
выводит найденный заранее ответ.

Решим задачу с помощью динамического программирования. Обозначим как 𝑢𝑝[𝑠][𝑘] количество массивов,
которые удовлетворяют описанным ограничениям, с суммой равной 𝑠, первым элементом равным 𝑘, а второй
элемент строго больше первого. Аналогично введём величину 𝑑𝑜𝑤𝑛[𝑠][𝑘], для количества таких массивов, где
второй элемент строго меньше первого.

Заметим, что 𝑢𝑝[𝑠][𝑠] = 𝑑𝑜𝑤𝑛[𝑠][𝑠] = 1. Для 𝑘 < 𝑠 значения можно вычислить по формулам:
𝑠−𝑘
∑︁
𝑢𝑝[𝑠][𝑘] = 𝑑𝑜𝑤𝑛[𝑠 − 𝑘][𝑖]
𝑖=𝑘+1

𝑘−1
∑︁
𝑑𝑜𝑤𝑛[𝑠][𝑘] = 𝑢𝑝[𝑠 − 𝑘][𝑖]
𝑖=1

Величина, которую требуется найти по условию задачи, равна 𝑢𝑝[𝑠][𝑘] + 𝑑𝑜𝑤𝑛[𝑠][𝑘], не забудем также
отдельный случай 𝑠 = 𝑘, когда ответ равен 1. Время работы такого алгоритма 𝑂(𝑠3 ).

Для оптимизации динамики можно использовать два подхода.

Подход 1: другая формула пересчёта.

Заметим, что формула для 𝑢𝑝[𝑠][𝑘] отличается от 𝑢𝑝[𝑠][𝑘 + 1] одним слагаемым: 𝑑𝑜𝑤𝑛[𝑠 − 𝑘][𝑘 + 1], поэтому
𝑢𝑝[𝑠][𝑘] = 𝑢𝑝[𝑠][𝑘 + 1] + 𝑑𝑜𝑤𝑛[𝑠 − 𝑘][𝑘 + 1].

Аналогично, 𝑑𝑜𝑤𝑛[𝑠][𝑘] = 𝑑𝑜𝑤𝑛[𝑠][𝑘 − 1] + 𝑢𝑝[𝑠][𝑘 − 1]. Теперь значения вычисляются за 𝑂(1) и время
подсчёта всех значений есть 𝑂(𝑠2 ). Следует обратить внимание, что значения 𝑢𝑝[𝑠][𝑘] следует вычислять по
убыванию 𝑘, а значения 𝑑𝑜𝑤𝑛[𝑠][𝑘] по возрастанию 𝑘.

Подход 2: префиксные суммы.

Введем дополнительные величины:

𝑘
∑︁
𝑠𝑢𝑚𝑈 𝑝[𝑠][𝑘] = 𝑢𝑝[𝑠][𝑖],
𝑖=1

𝑘
∑︁
𝑠𝑢𝑚𝐷𝑜𝑤𝑛[𝑠][𝑘] = 𝑑𝑜𝑤𝑛[𝑠][𝑖].
𝑖=1

Тогда
𝑢𝑝[𝑠][𝑘] = 𝑠𝑢𝑚𝐷𝑜𝑤𝑛[𝑠 − 𝑘][𝑠 − 𝑘] − 𝑠𝑢𝑚𝐷𝑜𝑤𝑛[𝑠 − 𝑘][𝑘],
𝑑𝑜𝑤𝑛[𝑠][𝑘] = 𝑠𝑢𝑚𝑈 𝑝[𝑠][𝑘 − 1].

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

Страница 13 из 34

Вам также может понравиться