Предметный тур. Информатика. 3 этап
Имя входного файла: стандартный ввод или input.txt.
Имя выходного файла: стандартный вывод или output.txt.
Ограничение по времени выполнения программы: 1 с.
Ограничение по памяти: 256 Мбайт.
Андрей пришел на олимпиаду, и ему выдали пароль из \(l\) символов, который содержал символы N, T, O, F, I, N, 2, 0, 2, 5. Каждый из них мог встречаться несколько раз или вообще не встречаться ни разу.
Андрей задумался: а какое минимальное число байт потребуется, чтобы сохранить пароли всех \(c\) участников, при условии, что на один пароль будет использоваться одинаковое целое число байт?
Формат входных данных
В первой строке дано одно целое число \(l\) \((10 \leqslant l \leqslant 50)\) — длина пароля.
Во второй строке дано одно целое число \(c\) \((20 \leqslant c \leqslant 200)\) — количество участников олимпиады.
Формат выходных данных
Вывести минимальное число байт, которое потребуется, чтобы сохранить пароли всех участников.
Тестовые данные
| Номер теста | Стандартный ввод | Стандартный вывод |
|---|---|---|
1 |
31 42 |
504 |
Пароль содержит 8 уникальных символов: N, T, O, F, I, 2, 0, 5. Для кодирования одного символа требуется: \[\log_2 8 = 3 \text{ бит}.\]
Для пароля длины \(l\): \[\text{Бит на пароль} = l \cdot 3.\]
1 байт = 8 бит. Чтобы найти целое число байт, округлим вверх: \[\text{Байт на пароль} = \left\lceil \frac{l \cdot 3}{8} \right\rceil.\] Эквивалентная формула для целочисленного деления: \[\text{Байт на пароль} = \frac{l \cdot 3 + 7}{8} \quad (\text{целочисленное деление}).\]
Умножим байты на пароль на количество участников \(c\): \[\text{Итого байт} = \left( \left\lceil \frac{3l}{8} \right\rceil \right) \cdot c.\]
Пример программы-решения
Ниже представлено решение на языке Python.
l = int(input())
c = int(input())
print((l * 3 + 7) // 8 * c)
Имя входного файла: стандартный ввод или input.txt.
Имя выходного файла: стандартный вывод или output.txt.
Ограничение по времени выполнения программы: 1 с.
Ограничение по памяти: 256 Мбайт.
Банк представляет собой квадрат \(15 \times 15\), в каждой ячейке хранится определенное число денег. Василий заранее знает, сколько денег в каждой ячейке.
Изначально Василий оказался в нижнем правом углу банка. Выход из банка в верхнем левом углу. Вася хочет добраться до выхода как можно быстрее, поэтому он будет двигаться от ячейки к ячейке только вверх или влево.
Вася хочет собрать как можно больше денег, но при этом он считает, что он обязан побывать в ячейке, в которой больше всего денег.
Определите, сколько максимум денег он может забрать из банка.
Формат входных данных
В первых 15 строках даны по 15 целых чисел \(a_{ij}\) (\(1 \leqslant a_{ij} \leqslant 100\)) — число денег в ячейке с координатой (\(i, j\)). Гарантируется, что максимальное значение ровно в одной ячейке.
Формат выходных данных
В первых 15 строках даны по 15 целых чисел \(a_{ij}\) (\(1 \leqslant a_{ij} \leqslant 100\)) — число денег в ячейке с координатой (\(i, j\)). Гарантируется, что максимальное значение ровно в одной ячейке.
Тестовые данные
| Номер теста | Стандартный ввод | Стандартный вывод |
|---|---|---|
1 |
58 76 81 25 79 27 50 81 34 22 98 75 42 71 83 36 1 22 84 57 22 22 55 22 70 30 19 6 12 66 84 69 73 27 93 37 8 26 41 69 91 10 65 9 40 5 48 8 97 55 91 37 13 64 98 82 36 84 89 36 15 2 3 49 34 22 67 69 20 2 42 98 90 62 91 39 60 12 31 53 31 56 5 45 46 9 6 15 49 67 2 18 16 14 18 86 65 50 72 53 14 85 26 11 84 58 99 46 79 94 56 66 19 54 80 85 13 18 25 56 28 41 49 37 60 27 6 39 54 49 90 82 66 57 52 68 16 39 33 32 96 65 55 67 58 76 62 70 70 64 2 1 69 76 14 76 66 100 52 56 38 29 87 55 40 53 8 9 86 92 13 67 11 40 49 92 14 38 94 71 77 14 1 47 36 75 54 39 34 77 21 90 4 77 18 32 5 37 86 67 94 25 60 94 36 15 85 94 9 96 88 36 83 5 35 65 53 31 32 70 68 71 48 88 96 |
1951 |
Примечания
Первый пример.
| 58 | 76 | 81 | 25 | 79 | 27 | 50 | 81 | 34 | 22 | 98 | 75 | 42 | 71 | 83 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 36 | 1 | 22 | 84 | 57 | 22 | 22 | 55 | 22 | 70 | 30 | 19 | 6 | 12 | 66 |
| 84 | 69 | 73 | 27 | 93 | 37 | 8 | 26 | 41 | 69 | 91 | 10 | 65 | 9 | 40 |
| 5 | 48 | 8 | 97 | 55 | 91 | 37 | 13 | 64 | 98 | 82 | 36 | 84 | 89 | 36 |
| 15 | 2 | 3 | 49 | 34 | 22 | 67 | 69 | 20 | 2 | 42 | 98 | 90 | 62 | 91 |
| 39 | 60 | 12 | 31 | 53 | 31 | 56 | 5 | 45 | 46 | 9 | 6 | 15 | 49 | 67 |
| 2 | 18 | 16 | 14 | 18 | 86 | 65 | 50 | 72 | 53 | 14 | 85 | 26 | 11 | 84 |
| 58 | 99 | 46 | 79 | 94 | 56 | 66 | 19 | 54 | 80 | 85 | 13 | 18 | 25 | 56 |
| 28 | 41 | 49 | 37 | 60 | 27 | 6 | 39 | 54 | 49 | 90 | 82 | 66 | 57 | 52 |
| 68 | 16 | 39 | 33 | 32 | 96 | 65 | 55 | 67 | 58 | 76 | 62 | 70 | 70 | 64 |
| 2 | 1 | 69 | 76 | 14 | 76 | 66 | 100 | 52 | 56 | 38 | 29 | 87 | 55 | 40 |
| 53 | 8 | 9 | 86 | 92 | 13 | 67 | 11 | 40 | 49 | 92 | 14 | 38 | 94 | 71 |
| 77 | 14 | 1 | 47 | 36 | 75 | 54 | 39 | 34 | 77 | 21 | 90 | 4 | 77 | 18 |
| 32 | 5 | 37 | 86 | 67 | 94 | 25 | 60 | 94 | 36 | 15 | 85 | 94 | 9 | 96 |
| 88 | 36 | 83 | 5 | 35 | 65 | 53 | 31 | 32 | 70 | 68 | 71 | 48 | 88 | 96 |
Для решения задачи разобьем ее на две части:
- Найдем координаты \((x_{max}, y_{max})\) ячейки с максимальным значением.
Разделим путь на два отрезка:
- от начальной точки \((15, 15)\) до \((x_{max}, y_{max})\);
- от \((x_{max}, y_{max})\) до конечной точки \((1, 1)\).
Пример программы-решения
Ниже представлено решение на языке Python.
def solve(a, start, end):
x1, y1 = start
x2, y2 = end
n = len(a)
m = len(a[0]) if n else 0
dp = [[0 for _ in range(m)] for _ in range(n)]
dp[x1][y1] = a[x1][y1]
for i in range(x1, x2 + 1):
for j in range(y1, y2 + 1):
if i == x1 and j == y1:
continue
dp[i][j] = a[i][j] + max(dp[i-1][j] if i > x1 else 0, dp[i][j-1] if j > y1 else 0)
return dp[x2][y2]
n, m = 15, 15
a = [list(map(int, input().split())) for _ in range(n)]
x, y = 0, 0
for i in range(n):
for j in range(m):
if a[x][y] < a[i][j]:
x, y = i, j
print(solve(a, (0, 0), (x, y)) + solve(a, (x, y), (n - 1, m - 1)) - a[x][y])
Для каждого из этих отрезков применим динамическое программирование, аналогичное задаче о максимальном пути в матрице с движениями только вверх и влево.
- Находим позицию максимального элемента \((x_{max}, y_{max})\).
Вычисляем максимальную сумму на пути от \((15, 15)\) до \((x_{max}, y_{max})\):
- Создаем матрицу \(dp1\) размером \(15 \times 15\).
- Инициализируем \(dp1[15][15] = a[15][15]\).
- Заполняем матрицу по правилу: \[dp1[i][j] = a[i][j] + \max(dp1[i+1][j], dp1[i][j+1])\] (с проверкой границ матрицы).
Вычисляем максимальную сумму на пути от \((x_{max}, y_{max})\) до \((1, 1)\):
- Создаем матрицу \(dp2\) размером \(15 \times 15\).
- Инициализируем \(dp2[x_{max}][y_{max}] = a[x_{max}][y_{max}]\).
- Заполняем матрицу по правилу: \[dp2[i][j] = a[i][j] + \max(dp2[i-1][j], dp2[i][j-1])\] (с проверкой границ матрицы).
- Итоговый результат: \(dp1[x_{max}][y_{max}] + dp2[1][1] - a[x_{max}][y_{max}]\) (вычитаем значение максимальной ячейки, так как оно учтено дважды).
Так как ограничения маленькие, то вместо написания динамики можно написать перебор всех путей от максимальной монеты до старта и до финиша.
Пример программы-решения
Ниже представлено решение на языке Python.
def solve():
# Чтение входных данных
grid = []
max_val = -1
max_pos = (-1, -1)
for i in range(15):
row = list(map(int, input().split()))
grid.append(row)
for j in range(15):
if row[j] > max_val:
max_val = row[j]
max_pos = (i, j)
start = (14, 14) # Нижний правый угол (индексы с 0)
end = (0, 0) # Верхний левый угол
# Функция для генерации всех возможных сумм до целевой точки
def generate_path_sums(start_pos, target_pos):
dx = start_pos[0] - target_pos[0] # Количество шагов вверх
dy = start_pos[1] - target_pos[1] # Количество шагов влево
total_steps = dx + dy
sums = {}
# Перебор всех комбинаций шагов
from itertools import combinations
for up_indices in combinations(range(total_steps), dx):
mask = 0
for pos in up_indices:
mask |= 1 << pos
x, y = start_pos
current_sum = grid[x][y]
valid = True
for i in range(total_steps):
if mask & (1 << i):
x -= 1 # Вверх
else:
y -= 1 # Влево
if x < 0 or y < 0 or x > 14 or y > 14:
valid = False
break
current_sum += grid[x][y]
if (x, y) == target_pos:
break
if valid and (x, y) == target_pos:
sums[mask] = current_sum
return sums
# Генерируем все суммы для первого отрезка
first_part = generate_path_sums(start, max_pos)
# Генерируем все суммы для второго отрезка
second_part = generate_path_sums(max_pos, end)
# Находим максимальную комбинацию
max_sum = 0
for sum1 in first_part.values():
for sum2 in second_part.values():
total = sum1 + sum2 - max_val
if total > max_sum:
max_sum = total
print(max_sum)
solve()
Имя входного файла: стандартный ввод или input.txt.
Имя выходного файла: стандартный вывод или output.txt.
Ограничение по времени выполнения программы: 1 с.
Ограничение по памяти: 256 Мбайт.
Банкир должен выдать на сдачу \(x\) руб. Сколькими способами он может это сделать, если у него есть монеты достоинством 1, 2, 5 и 10 руб.
Например, если банкиру надо сдать 25 руб., то существует 64 способа (способы считаются различными, если наборы различаются хотя бы одной монетой; порядок монет неважен).
Формат входных данных
В первой строке дано одно число \(x\) (\(1 \leqslant x \leqslant 2025\)) — сколько сдачи должен выдать банкир.
Формат выходных данных
Выведите количество способов сдать сдачу.
Тестовые данные
| Номер теста | Стандартный ввод | Стандартный вывод |
|---|---|---|
1 |
25 |
64 |
Используем динамическое программирование по сумме. Определим \(dp[i]\) как количество способов набрать сумму \(i\) заданными монетами.
- Инициализация: \(dp[0] = 1\) (существует один способ выдать 0 руб. — не выдавать ничего).
- Для каждой монеты достоинством \(c \in \{1, 2, 5, 10\}\) для всех сумм \(i\) от \(c\) до \(x\) обновляем значение: \(dp[i] += dp[i - c]\).
- Результат: \(dp[x]\).
Пример программы-решения
Ниже представлено решение на языке Python.
n = int(input())
coins = [1, 2, 5, 10]
dp = [0] * (n + 1)
dp[0] = 1
for coin in coins:
for j in range(coin, n + 1):
dp[j] += dp[j - coin]
print(dp[n])
Перебираем все возможные комбинации монет, сумма которых равна \(x\).
- Для всех возможных количеств монет 10 рублей (\(0 \leqslant a \leqslant \lfloor x/10 \rfloor\)).
- Для всех возможных количеств монет 5 рублей (\(0 \leqslant b \leqslant \lfloor (x - 10a)/5 \rfloor\)).
- Для всех возможных количеств монет 2 рублей (\(0 \leqslant c \leqslant \lfloor (x - 10a - 5b)/2 \rfloor\)).
- Оставшуюся сумму \(d = x - 10a - 5b - 2c\) покрываем монетами 1 руб.
- Увеличиваем счетчик способов на единицу для каждой валидной комбинации \((a, b, c, d)\).
Пример программы-решения
Ниже представлено решение на языке Python.
n = int(input())
cnt = 0
for i in range(n // 10 + 1):
ost = n - i * 10
for j in range(ost // 5 + 1):
ost1 = ost - j * 5
for k in range(ost1 // 2 + 1):
cnt += 1
print(cnt)
Имя входного файла: стандартный ввод или input.txt.
Имя выходного файла: стандартный вывод или output.txt.
Ограничение по времени выполнения программы: 1 с.
Ограничение по памяти: 256 Мбайт.
Банкир придумал новую игру с монетами. Всего у него есть \(g\) золотых монет и \(s\) серебряных. Необходимо сложить монеты в стопки по три штуки. Стопки, в которых все три монеты одинаковые, считаются скучными. Помогите понять, сколько максимум нескучных стопок может составить банкир.
Формат входных данных
Первая строка содержит одно целое число \(g\) (\(1 \leqslant g \leqslant 10^{12}\)) — количество золотых монет.
Вторая строка содержит одно целое число \(s\) (\(1 \leqslant s \leqslant 10^{12}\)) — количество серебряных монет.
Формат выходных данных
Вывести одно целое число — максимальное число не скучных стопок по три монеты.
Тестовые данные
| Номер теста | Стандартный ввод | Стандартный вывод |
|---|---|---|
1 |
3 4 |
2 |
2 |
3 10 |
3 |
Разберем несколько случаев.
Если \(g > s\), то можно их поменять местами, количество стопок от этого не изменится. Если \(g < s/2\), то можно сделать только \(g\) стопок.
Если разница не столь велика, можно создать \(g-s\) стопок, выровняв количество золотых и серебряных монет, и затем можно делать стопки: 2 золотые монеты и 1 серебряная, и 2 серебряные монеты и 1 золотая. Когда в каждом типе останется менее 3, в случае остатка 2 можно сделать еще одну стопку.
Пример программы-решения
Ниже представлено решение на языке Python.
n = int(input())
m = int(input())
if n < m:
n, m = m, n
if n >= 2 * m:
print(m)
else:
print((n - m) + (2 * m - n) // 3 * 2 + (1 if (2 * m - n) % 3 > 1 else 0))
Имя входного файла: стандартный ввод или input.txt.
Имя выходного файла: стандартный вывод или output.txt.
Ограничение по времени выполнения программы: 1 с.
Ограничение по памяти: 256 Мбайт.
Начинающий инвестор Василий узнал о двоичных финансовых инструментах, которые считаются надежными. Их номиналы состоят только из цифры \(2\), например, \(2\), \(22\), \(222\) и так далее. Василий хочет вложить сумму \(x\), используя только эти инструменты. Сумма вложения равна произведению номиналов выбранных инструментов (каждый номинал можно использовать несколько раз, например, \(8 = 2 \cdot 2 \cdot 2\), \(44 = 22 \cdot 2\)). Однако не все \(x\) возможно представить таким образом, поэтому Василий хочет инвестировать сумму \(y\) (где \(x \leqslant y\)), которую можно разложить на произведение двоичных номиналов.
Помогите Василию найти наименьшее число \(y\), удовлетворяющее условиям.
Формат входных данных
В первой строке содержится одно целое число \(x\) (\(2 \leqslant x \leqslant 10^{18}\)).
Формат выходных данных
Вывести одно целое число \(y\), которое можно представить в виде произведения двоичных номиналов.
Тестовые данные
| Номер теста | Стандартный ввод | Стандартный вывод |
|---|---|---|
1 |
70 |
88 |
С помощью рекурсии сгенерируем все числа, которые можно получить в качестве произведения чисел, состоящих только из двоек. Таких чисел немного. После этого находим наименьшее число \(y\), которое можно представить в виде произведения двоичных чисел.
Пример программы-решения
Ниже представлено решение на языке Python.
correct = set()
all = []
for i in range(18):
all.append(int("2" * (i + 1)))
def gen(cur, last):
global correct
global all
if cur > int(1e19):
return
correct.add(cur)
for i in range(last, 18):
gen(cur * all[i], i)
x = int(input())
gen(1, 0)
correct = sorted(list(correct))
for y in correct:
if y >= x:
print(y)
break
