Задание №5. Автомат: из числа N делаем число R
Что от тебя хотят
Есть «автомат» с инструкцией: берём N, переводим в двоичную запись, что-то с ней делаем (дописываем, считаем, переворачиваем) и получаем число R. Тебя просят найти либо R для конкретного N, либо наименьшее N, при котором R получится нужным.
Четыре команды, которых хватит
| Что нужно | Команда |
|---|---|
| Двоичная запись числа N | bin(n)[2:] (срез убирает приставку 0b) |
| Количество единиц | b.count("1") |
| Из двоичной записи обратно в число | int(b, 2) |
| Дописать цифру справа | b = b + "0" |
Способ 1: перебор «вперёд»
Если автомат простой, а ответ небольшой, пробуй N подряд: 1, 2, 3... Для каждого строй R по инструкции и проверяй условие. Первое подошедшее N и есть наименьшее.
К двоичной записи числа N справа дублируется последняя цифра. Затем справа дописывается бит чётности (остаток от деления количества единиц на 2), и та же операция выполняется для получившейся записи ещё раз. Результат — двоичная запись числа R. Найдите наименьшее N, при котором R больше 97.
Код из первого окна выдаёт 13: двоичная запись 1101, после дублирования 11011, после двух битов чётности 1101100, это 108. А у 12 получается 1100000, ровно 96, не хватило совсем чуть-чуть.
Способ 2: думаем «назад»
Если R огромное, а ответ получается в миллиардах, перебор N подряд застрянет. Тогда идём от результата обратно.
По двоичной записи числа N подсчитали количество единиц и количество нулей. Эти два числа записали в двоичной системе один за другим: сначала единицы, потом нули. Получили двоичную запись числа R. Найдите наименьшее N, при котором R = 314.
- Двоичная запись 314 это
100111010. Это два числа, склеенные подряд: сначала число единиц, потом число нулей. - Не знаем, где граница. Пробуем все места разреза, но справа часть не может начинаться с нуля: в двоичной записи числа ведущих нулей нет.
- Для каждого разреза получаем количество единиц и нулей. Например,
10011и1010означают 19 единиц и 10 нулей. - Самое маленькое число с такими количествами: сначала единица, потом все нули, потом остальные единицы. Для 19 и 10 это
1+0000000000+ 18 единиц. - Среди всех разрезов выбираем наименьшее число. Результат второго окна: 268697599.
Разновидности и прототипы задания на экзамене
Код решения на Python
Запустить код в онлайн-песочницеfor n in range(1, 1000):
b = bin(n)[2:]
b = b + b[-1]
b = b + str(b.count("1") % 2)
b = b + str(b.count("1") % 2)
r = int(b, 2)
if r > 97:
print(n)
break
r = bin(314)[2:]
best = 10 ** 20
for cut in range(1, len(r)):
left = r[:cut]
right = r[cut:]
if right[0] == "0":
continue
ones = int(left, 2)
zeros = int(right, 2)
n = int("1" + "0" * zeros + "1" * (ones - 1), 2)
best = min(best, n)
print(best)
Типичные ошибки
binbin(5) даёт '0b101': приставка попадёт в подсчёты и в склейку.bin(n)[2:].right[0] == "0".ГРОБ №5: Автомат в троичной записи
Инструкция работает не с двоичной, а с троичной записью. У Python нет готовой функции для перевода числа в троичную систему.
s = "", пока n > 0 пиши s = str(n % 3) + s и делай n = n // 3. Обратно: int(s, 3).Лайфхаки на экзамене
- Количество единиц в двоичной записи считается командой
b.count("1"). Нули считаются так же:b.count("0"). - Наименьшее число с заданными количествами единиц и нулей: сначала
1, затем все нули, затем все остальные единицы. - Условие «наименьшее N»: идём по N в порядке возрастания и останавливаемся на первом подходящем. Условие «наибольшее»: идём вниз или берём максимум.