Киоск: сдача без сдачи
Условие
Ты зашёл в школьный киоск. У тебя в кармане лежат несколько купюр/монет с фиксированными номиналами. Продавец вредничает и просит заплатить ровно без сдачи. Каждую купюру можно использовать не больше одного раза.
Определи, получится ли набрать ровно нужную сумму.
Формат ввода
В первой строке записаны два целых числа n и S — количество купюр и нужная сумма. Во второй строке записаны n целых чисел a1, a2, ..., an — номиналы купюр.
Формат вывода
Выведи YES, если можно выбрать некоторые купюры так, чтобы их сумма была ровно S. Иначе выведи NO.
Ограничения
1 ≤ n ≤ 181 ≤ ai ≤ 10000 ≤ S ≤ 18000
Пример
Ввод:
5 11
1 2 5 9 10
Вывод:
YES
(например, 1 + 10 = 11)
Как решать — идея подхода
Приём: Перебор подмножеств битмаской
Ключевое наблюдение: купюр всего до 18, значит количество всех вариантов выбора «взять/не взять» равно 2^n — это всего 262144. Такой перебор легко укладывается по времени.
Приём: битмаска (binary mask) — число от 0 до 2^n - 1, где i-й бит показывает, берём ли купюру a[i]. Почему работает: каждый набор купюр однозначно соответствует своей маске, и мы гарантированно проверяем все возможные подмножества.
План решения:
- Считать
n,Sи массивa. - Для каждой
maskв диапазоне0 .. (1<<n)-1: - Посчитать сумму выбранных купюр: пройти по
i=0..n-1и если бит включён — добавитьa[i]. - Если сумма стала равна
S, сразу вывестиYESи закончить. - Если все маски проверены и совпадения нет — вывести
NO.
Мини-сниппет проверки бита:
if (mask >> i) & 1: s += a[i]
Сложность: O(n * 2^n), при n=18 это около 4–5 миллионов операций.
Частая грабля: забыть, что сумма S может быть 0. Тогда подходит пустое множество (маска 0), и ответ должен быть YES.
Разберись руками
Нужно заплатить ровно 11, а купюры такие: 1, 2, 5, 9, 10. Каждую купюру можно взять или не взять, но нельзя взять дважды. Проверим на руках, как искать подходящий набор.
- Для разогрева возьмём из набора только три купюры: 1, 2 и 10. Отметь ВСЕ варианты (подмножества), где сумма ровно 11.
- Посчитай руками сумму для найденного варианта: сколько будет 1 + 10?
- Если делать честный полный перебор для всех 5 купюр (каждую либо берём, либо нет), сколько всего вариантов наборов нужно проверить?
Идея: Считай, что у каждой купюры есть два решения: взять или не взять. Перебери все такие варианты наборов, для каждого быстро посчитай сумму, и как только встретится ровно нужная сумма — отвечай YES; если перебрал всё и не нашёл — NO.
Решить задачу с автопроверкой на Python →
Куда дальше
- С нуля до олимпиады: маршрут — сколько занимает язык, какие приёмы нужны и к какому этапу это ведёт
- БВИ и льготы при поступлении — какой диплом что даёт и сколько лет он действует
- Перечневые олимпиады по информатике — олимпиады перечня Минобрнауки, их уровни и что нужно к диплому