Ошибка Кода

Разбор заданий, сложный уровень
B. задача 2 сложная
Миша заполнял таблицу истинности функции F=(a → b) ∧ (b → ¬c) ∧ (c ≡ ¬d), но успел заполнить лишь фрагмент из четырёх различных её строк, даже не указав, какому столбцу таблицы соответствует каждая из переменных a,b,c,d.
Таблица истинности
Определите, какому столбцу таблицы истинности функции F соответствует каждая из переменных a,b,c,d.
В ответе напишите буквы a,b,c,d в том порядке, в котором идут соответствующие им столбцы (сначала буква, соответствующая первому столбцу; затем буква, соответствующая второму столбцу, и т. д.). Буквы в ответе пишите подряд, никаких разделителей между буквами ставить не нужно.
Решение
Для решения этой задачи мы используем библиотеку itertools, которая предоставляет удобные функции для создания итераторов.
Основная идея заключается в том, чтобы перебрать все возможные комбинации значений переменных и все возможные перестановки столбцов таблицы истинности, чтобы проверить, соответствуют ли они заданной логической функции.

  1. Сначала определяем функцию F, которая реализует заданную логическую функцию.
  2. Затем генерируем все возможные комбинации значений переменных x1,x2,x3,x4 и создаем фрагмент таблицы истинности.
  3. Проверяем, уникальны ли все строки в этой таблице.
  4. Если уникальны, перебираем все возможные перестановки столбцов (abcd, abdc, acbd, …).
  5. Для каждой перестановки проверяем, соответствуют ли значения функции F значениям в таблице истинности.
  6. Если соответствуют, выводим эту перестановку.

Таким образом, мы находим все перестановки столбцов таблицы истинности, которые соответствуют заданной логической функции.

Давайте разберем код построчно:
# Импорт нужных функций из модуля itertools
from itertools import *

# Определение функции F, реализующей логическую функцию F
def F(a, b, c, d): # В данном случае необходимо 
    return (a <= b) and (b <= (not c)) and (c == (not d))

# Генерация всех возможных комбинаций значений переменных x1, x2, x3, x4
for x1, x2, x3, x4 in product((0, 1), repeat=4):
    
    # Создание фрагмента таблицы истинности
    t = [(1, 1, 0, x1), (x2, 0, 1, 0), (1, 0, x3, 1), (0, x4, 0, 1)]
    
    # Проверка на уникальность строк в таблице
    if len(set(t)) == len(t):
        
        # Перебор всех возможных перестановок столбцов (abcd, abdc, acbd, ...)
        for p in permutations('abcd'):
            
            # Проверка, что для данной перестановки значения F совпадают с заданными в таблице
            if [F(**dict(zip(p, r))) for r in t] == [1, 1, 1, 1]:
                
                # Вывод найденной перестановки
                print(*p, sep='')

Ответ: bacd
C. задача 5 сложная

На вход программы подаётся натуральное число N. Программа преобразует это число в новое число R следующим образом:

  1. Преобразуется число N в его троичное представление.
  2. Если длина троичной записи числа N нечетная, в начало добавляется цифра 1.
  3. Далее эта запись обрабатывается согласно следующему алгоритму:
    1. Если сумма цифр числа N четная, то к троичной записи дописываются первые две цифры этой записи в конец числа.
    2. Если сумма цифр числа N нечетная, то остаток от деления N на 5 переводится в троичную систему и дописывается в конец числа.
  4. Далее если полученное число начинается на «2», то этот разряд удаляют (не забывай про удаление незначащих нулей, которые могут появиться).
  5. Далее если число оканчивается на две одинаковые цифры, то удаляют последний разряд.Полученное число переводится в десятичную систему и выводится на экран.
Пример:
Для N=14:
14 → 112 → 1112 → 111211 → 11121 → 124
Определите минимальное число R, большее 150, которое может быть получено с помощью описанного алгоритма.
В ответе укажите это число в десятичной системе счисления.
Решение
Для решения этой задачи мы используем несколько шагов:
  1. Сначала переводим число N в троичную систему счисления.
  2. Затем корректируем получившуюся троичную запись числа N в соответствии с разными правилами, которые зависят от четности длины троичной записи и четности суммы его цифр.
  3. После всех преобразований переводим число обратно в десятичную систему.
  4. Если получившееся число R больше 150, добавляем его в множество.
  5. В конце выводим минимальное число из этого множества.

Этот процесс повторяется для каждого N в заданном диапазоне от 1 до 100000.

Важно отметить, что мы используем множество для хранения чисел R, чтобы автоматически избавиться от дубликатов, и в конце просто находим минимальное значение в этом множестве.

Подводный камень в этой задаче заключается в том, что первая цифра «2» удаляется из троичной записи числа. Это может значительно уменьшить итоговое значение R, что, в свою очередь, может привести к тому, что вы пропустите минимальное значение R>150 при переборе только ограниченного диапазона чисел N. Поэтому для получения точного ответа важно выбрать достаточно большой диапазон для N.

Давайте разберем код построчно:
# Функция для перевода числа в троичную систему счисления
def to_ternary(n):
    if n == 0:
        return "0"
    ternary = []  # Список для хранения цифр троичного числа
    while n:
        n, r = divmod(n, 3)  # Делим n на 3 и сохраняем результат и остаток
        ternary.append(str(r))  # Добавляем остаток в список
    return ''.join(reversed(ternary))  # Возвращаем перевернутую строку

a = set()  # Множество для хранения чисел R

# Основной цикл, в котором N пробегает значения от 1 до 100000
for N in range(1, 100000):
    n = to_ternary(N)  # Переводим N в троичную систему
    # Проверяем четность длины троичной записи числа
    if len(n) % 2 != 0:
        n = '1' + n  # Добавляем 1 в начало, если длина нечетная
    
    # Проверяем четность суммы цифр числа N
    if sum(int(digit) for digit in str(N)) % 2 == 0:
        n = n + n[:2]  # Добавляем первые две цифры в конец, если сумма четная
    else:
        n = n + to_ternary(N % 5)  # Иначе добавляем остаток от деления N на 5, переведенный в троичную систему
    
    # Удаляем первую цифру, если она равна "2"
    if n[0] == "2":
        n = n[1:]
    
    # Удаляем последний разряд, если последние две цифры одинаковы
    if n[-1] == n[-2]:
        n = n[:-1]
    
    R = int(n, 3)  # Переводим полученное троичное число обратно в десятичную систему
    if R > 150:  # Если R больше 150, добавляем его в множество
        a.add(R)

print(min(a))  # Выводим минимальное значение из множества

Ответ: 151
D. задача 8 сложная
Рассмотрим шестнадцатеричные четырёхзначные числа.

Сколько существует таких чисел, у которых:

  1. В записи числа присутствует две четные и две нечетные цифры.
  2. Сумма четных цифр равна сумме нечетных цифр.
  3. Ни одна из цифр не повторяется.
Для решения этой задачи мы используем перебор всех возможных четырёхзначных перестановок шестнадцатеричных чисел.
  1. Сначала задаем строки четных и нечетных шестнадцатеричных цифр.
  2. Затем инициализируем счетчик, который будет отслеживать количество перестановок, удовлетворяющих условиям задачи.
  3. Перебираем все возможные четырёхзначные перестановки шестнадцатеричных чисел.
  4. Убеждаемся, что первая цифра в перестановке не ноль.
  5. Считаем количество четных и нечетных цифр в каждой перестановке, а также их суммы.
  6. Проверяем, удовлетворяют ли эти значения условиям задачи (два четных и два нечетных элемента, их суммы равны).
  7. Если условия выполнены, увеличиваем счетчик на 1.

В итоге, счетчик будет содержать количество перестановок, которые удовлетворяют всем условиям задачи.

Подводный камень в этой задаче заключается в том, что числа представлены в шестнадцатеричной системе счисления. Это означает, что кроме десятичных цифр от 0 до 9, в числе могут встречаться и буквы от A до F, которые представляют числа от 10 до 15 в десятичной системе.

Из-за этого, при подсчете количества четных и нечетных цифр, а также их сумм, нужно быть очень внимательным. Например, буква 'A' в шестнадцатеричной системе счисления представляет число 10 в десятичной, которое является четным.

Так что когда вы перебираете все возможные перестановки, удостоверьтесь, что правильно обрабатываете и числовые, и буквенные символы.

Давайте разберем код построчно:
from itertools import permutations  # Импорт функции для генерации перестановок

even_digits = "02468ACE"  # Строка четных шестнадцатеричных цифр
odd_digits = "13579BDF"  # Строка нечетных шестнадцатеричных цифр

count_permutations = 0  # Счетчик нужных перестановок

# Цикл по всем возможным четырёхзначным перестановкам шестнадцатеричных чисел
for i in permutations('0123456789ABCDEF', 4):
    if i[0] != "0":  # Первая цифра не должна быть нулём
        # Подсчет количества четных и нечетных цифр в перестановке
        even_count = sum(1 for digit in i if digit in even_digits)
        odd_count = sum(1 for digit in i if digit in odd_digits)
        
        # Подсчет суммы четных и нечетных цифр в перестановке
        even_sum = sum(int(digit, 16) for digit in i if digit in even_digits)
        odd_sum = sum(int(digit, 16) for digit in i if digit in odd_digits)
        
        # Проверка условий задачи
        if even_count == 2 and odd_count == 2 and even_sum == odd_sum:
            count_permutations += 1  # Увеличение счетчика

print(count_permutations)  # Вывод результата

Ответ: 1560
E. задача 9 сложная
У вас есть файл электронной таблицы в формате CSV с именем 9.csv.

В каждой строке этого файла содержится четыре записи: год рождения, месяц рождения, день рождения и пол (м или ж).

Пример строки:
1973;5;23;ж
файл 9.csv можно открыть используя open()
Ваша задача — написать программу, которая определит количество женщин, родившихся в високосный год, которые в октябре 2023 года будут праздновать день рождения.
Год считается високосным, если он делится на 4, но при этом не делится на 100, либо если он делится на 400.
Решение
Для решения этой задачи мы используем функцию для определения високосного года и простой перебор всех записей в файле.
  1. Сначала определяем функцию, которая проверяет, является ли год високосным.
  2. Затем открываем файл и начинаем читать его построчно.
  3. Для каждой строки разбиваем её на четыре части: год, месяц, день и пол.
  4. Преобразуем год и месяц в числовой формат для дальнейших проверок.
  5. Проверяем, удовлетворяет ли каждая строка условиям задачи: женский пол, високосный год и десятый месяц.
  6. Если все условия выполнены, увеличиваем счетчик на 1.

Подводным камнем здесь может быть формат данных в файле. Убедитесь, что все данные преобразованы в нужный формат и что функция для проверки високосного года правильно работает для всех возможных вариантов годов в файле.

В итоге, счетчик будет содержать количество женщин, родившихся в октябре високосного года.

Давайте разберем код построчно:
# Функция для определения, является ли год високосным
def is_leap_year(year):
    return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)

# Путь к файлу
file_path = '9.csv'

# Счетчик для подсчета количества женщин, соответствующих условиям
count = 0

# Открытие файла для чтения
with open(file_path, 'r') as file:
    for line in file:
        # Разбиение строки на составляющие
        year, month, day, gender = line.strip().split(';')
        
        # Преобразование года и месяца в целочисленный формат
        year = int(year)
        month = int(month)
        
        # Проверка условий и увеличение счетчика при совпадении
        if gender == 'ж' and is_leap_year(year) and month == 10:
            count += 1

# Вывод результата
print(count)

Ответ: 12
F. задача 12 сложная
Исполнитель редактор принимает на вход строку цифр и может выполнять две команды:
  1. Заменить (v, w)
    Эта команда заменяет в строке первое слева вхождение цепочки v на цепочку w. Например, выполнение команды заменить (333, 77) преобразует строку 333233 в строку 77233. Если в строке нет вхождений цепочки v, то выполнение команды заменить (v, w) не меняет эту строку.
  2. Нашлось (v)
    Эта команда проверяет, встречается ли цепочка v в строке исполнителя Редактор. Если она встречается, то команда возвращает логическое значение «истина», в противном случае возвращает значение «ложь». Строка исполнителя при этом не изменяется.
Дана программа для Редактора:
НАЧАЛО 
ПОКА нашлось (63) ИЛИ нашлось (69) ИЛИ нашлось (93) 
     ЕСЛИ нашлось (63) 
          ТО заменить (63, 36) 
     КОНЕЦ ЕСЛИ ЕСЛИ нашлось (69) 
          ТО заменить (69, 96) 
     КОНЕЦ ЕСЛИ 
     ЕСЛИ нашлось (93) 
          ТО заменить (93, 39) 
     КОНЕЦ ЕСЛИ 
КОНЕЦ ПОКА 
КОНЕЦ
На вход приведённой ниже программы поступает строка из 150 цифр, содержащая по 50 цифр 3, 6 и 9, расположенных в произвольном порядке.
Определите, какие цифры будут находиться на 42-м, 100-м и 144-м местах строки, получившейся в результате выполнения программы.
Цифры в строке нумеруются последовательно слева направо, самая левая имеет номер 1, следующая — номер 2 и т. д.

В ответе запишите три полученные цифры подряд без пробелов и разделителей в порядке возрастания номеров их мест в получившейся строке. Так, например, если бы на 42-м месте стояла цифра 1, на 100-м — 2, а на 144-м — 3, то был бы ответ 123.

Решение
Для решения этой задачи мы используем следующие шаги:
  1. Сначала создаем строку, состоящую из 50 символов '6', 50 символов '3' и 50 символов '9'.
  2. Перемешиваем символы в этой строке случайным образом.
  3. Ищем в строке комбинации '63', '69' и '93', и меняем их местами на '36', '96' и '39' соответственно. Этот процесс продолжается, пока возможны замены.
  4. В конце выводим символы строки с индексами 41, 99 и 143.

Подводный камень в этой задаче может заключаться в порядке замен. Например, если строка содержит комбинацию «639», замена «63» на «36» приведет к новой комбинации «369», которая в последствии может снова измениться. Поэтому важно внимательно следить за порядком замен, чтобы удостовериться, что все замены произведены корректно.

В итоге, программа выведет символы с требуемыми индексами после всех замен.

Давайте разберем код построчно:
from random import shuffle
# Создание строки из 50 '6', 50 '3' и 50 '9'
line = ''
for s in '639': line += s * 50

# Перемешивание символов строки
line = list(line)
shuffle(line)
line = ''.join(line)

# Пока в строке есть комбинации '63', '69' или '93' меняем их местами
while '63' in line or '69' in line or '93' in line:
    if '63' in line:
        line = line.replace('63', '36', 1)
    if '69' in line:
        line = line.replace('69', '96', 1)
    if '93' in line:
        line = line.replace('93', '39', 1)

# Вывод требуемых символов строки
print(line[42 - 1], line[100 - 1], line[144 - 1], sep='')

Ответ: 396
G. задача 13 сложная
Вы работаете системным администратором в средней школе. Руководство школы решило оснастить классы компьютерами для проведения уроков информатики. Вам поручено разбить имеющуюся компьютерную сеть на отдельные подсети так, чтобы каждый класс имел свою отдельную подсеть.

Ваша основная сеть имеет IP-адрес 172.16.8.0 и маску подсети 255.255.252.0.

В каждом классе будет 30 учеников и 1 учитель, что в сумме составляет 31 компьютер.

Каждая подсеть должна иметь минимум два дополнительных адреса: один для адреса сети и один для широковещательного адреса.

Определите, сколько максимум классов можно оснастить компьютерами, используя указанную сеть.
Решение
Для решения этой задачи мы используем следующую логику:
  1. Сначала определим, сколько IP-адресов есть в вашей исходной подсети. В данном случае, маска подсети 255.255.252.0 соответствует 22 битам для сетевой части IP-адреса. Это означает, что у вас есть 2^32−22=1024 адреса в подсети.
  2. Затем определим, сколько IP-адресов требуется для одного класса. У вас в каждом классе 31 компьютер (30 учеников + 1 учитель), и нужно еще добавить 2 адреса: один для адреса сети и один для широковещательного адреса. Итого, на один класс требуется 33 IP-адреса.
  3. Далее, нам нужно найти ближайшую степень двойки, которая больше или равна 33. Это 64. Подсеть должна иметь размер, являющийся степенью двойки, чтобы эффективно разделить исходную подсеть.
  4. Теперь мы можем определить, сколько подсетей (и, соответственно, классов) мы можем создать. Для этого разделим общее количество адресов в исходной подсети (1024) на количество адресов в одной подсети (64). Получим, что максимальное количество классов равно 1024/64​=16.

Итак, вы можете оснастить компьютерами максимум 16 классов, используя указанную сеть.

Давайте разберем код построчно:
import math

# Исходная подсеть и количество адресов в ней
original_subnet = "192.168.10.0/23"
original_subnet_size = 2 ** (32 - int(original_subnet.split("/")[-1]))

# Минимальное количество устройств в каждом отделе
min_devices_per_department = 25

# Вычисляем необходимое количество адресов в каждой подсети
required_addresses_per_subnet = min_devices_per_department + 2  # +2 для адреса сети и адреса широковещательной передачи

# Находим ближайшую степень двойки, которая больше или равна необходимому количеству адресов
subnet_size = 2 ** math.ceil(math.log2(required_addresses_per_subnet))

# Вычисляем максимальное количество подсетей
max_subnets = original_subnet_size // subnet_size

# Расчитываем адреса и маски для каждой подсети
subnets = []  # Создаем пустой список для хранения информации о каждой подсети
current_address = 0  # Устанавливаем текущий адрес на 0, это будет начальный адрес для первой подсети

for _ in range(max_subnets):  # Цикл, который повторяется столько раз, сколько возможных подсетей
    subnet_address = f"192.168.10.{current_address}"  # Формируем адрес подсети на основе текущего адреса
    subnet_mask = 32 - int(math.log2(subnet_size))  # Вычисляем маску подсети на основе размера подсети
    subnets.append((subnet_address, subnet_mask))  # Добавляем кортеж с адресом и маской подсети в список
    current_address += subnet_size  # Увеличиваем текущий адрес на размер подсети для следующей итерации

print(max_subnets)
Ответ: 16
H. задача 14 сложная
Результат выражения 3Bz4C​35 +A12Fy​19 делится на 7, где z и y — цифры в используемых системах счисления.
Найдите максимальное значение суммы z+y, когда это возможно.
В качестве ответа приведите десятичную запись полученной суммы.
Решение
Для решения этой задачи мы используем следующую стратегию:
  1. Создадим пустой список для хранения возможных значений суммы z+y.
  2. Переберем все возможные значения z от 0 до 34 (потому что используется 35-ричная система счисления).
  3. Для каждого z, переберем все возможные значения y от 0 до 18 (потому что используется 19-ричная система счисления).
  4. После того как у нас есть пара (z,y), мы подставляем эти значения в выражение и переводим его в десятичную систему счисления.
  5. Проверяем, делится ли полученное число на 7. Если делится, то добавляем значение z+y в наш список.
  6. В конце находим максимальное значение суммы z+y из списка.

В результате выполнения этого алгоритма, вы получите максимальное значение z+y, при котором выражение делится на 7.

Давайте разберем код построчно:
a = []  # Создание пустого списка для хранения возможных значений суммы z+y

# Перебор всех возможных значений z (от 0 до Y) в 35-ричной системе счисления
for z in '0123456789ABCDEFGHIJKLMNOPQRSTUVWXY':
    # Перебор всех возможных значений y (от 0 до I) в 19-ричной системе счисления
    for y in '0123456789ABCDEFGHI':
        # Вычисление значения выражения 3Bz4C_{35} + A12Fy_{19} в 10-ричной системе счисления
        n = int(f'3B{z}4C', 35) + int(f'A12F{y}', 19)
        
        # Проверка, делится ли полученное значение на 7
        if n % 7 == 0:
            # Если делится, добавляем сумму z+y в список a
            a.append(int(z, 35) + int(y, 19))

# Вывод максимального значения суммы z+y из списка a
print(max(a))

Ответ: 46
I. задача 15 сложная
На числовой прямой даны два отрезка P=[3, 87] и Q=[50, 72].
Укажите наибольшую возможную длину такого отрезка A, что формула (x ∈ P) ∧ ¬((x ∈ A) ≡ (x ∈ Q))∨¬((x∈ Q) ∨ (x∈ A)) тождественно истинна (то есть принимает значение 1 при любых значении переменной x)?
Решение
Для решения этой задачи мы используем метод перебора всех возможных диапазонов a и проверим, соответствует ли каждый диапазон заданным условиям.
Схема решения такова:

  1. У нас уже есть заданные диапазоны p и q.
  2. Нашей задачей является нахождение такого диапазона a, чтобы для всех чисел x от 1 до 99 выполнялось определенное условие.
  3. Мы используем двойной цикл для перебора всех возможных диапазонов a.
  4. Внутри этих циклов мы перебираем все x от 1 до 99 и проверяем, выполняется ли для них условие.
  5. Если условие выполняется для всех x, мы обновляем максимально возможную длину диапазона a.
  6. В конце программы выводим эту максимальную длину.

Этот метод даст нам диапазон a, который соответствует условиям задачи, и его максимальную возможную длину.

Давайте разберем код построчно:
# Определение диапазонов p и q
p = range(3, 87 + 1) # Диапазон чисел от 3 до 87 включительно
q = range(50, 72 + 1) # Диапазон чисел от 50 до 72 включительно

# Инициализация максимальной длины диапазона a
l_max = 0

# Двойной цикл для определения левой и правой границ диапазона a
for left in range(2, 88 + 1): # Перебор возможных левых границ диапазона a от 2 до 88 включительно
    for right in range(left + 1, 88 + 1): # Перебор возможных правых границ диапазона a начиная с левой границы + 1 до 88 включительно
        a = range(left, right + 1) # Определение текущего диапазона a
        ok = True # Флаг, указывающий на соответствие условиям задачи
        
        # Перебор чисел от 1 до 99 включительно
        for x in range(1, 100):
            # Проверка условий задачи для каждого x
            f = (x in p) and (not ((x in a) == (x in q))) or (not ((x in a) or (x in q)))
            if f == 0: # Если условие не выполнилось для текущего x
                ok = False # Устанавливаем флаг в False
                break # Прерываем цикл
        
        # Если для всех x условие выполнилось
        if ok:
            l_max = max(l_max, right - left) # Обновляем максимальную длину диапазона a

# Вывод длины диапазона a с учетом того, что правая граница не включается в диапазон
print(l_max + 1)

Ответ: 47
J. задача 16 сложная
Алгоритм вычисления значения функции F (n), где n — целое неотрицательное число, задан следующими соотношениями:
F(n)=0, при n≤1,
F(n)=n+F(n/6−2), когда n>1 и делится на 6
F(n)=n+F(n+6), когда n>1 и не делится на 6.
Чему равно минимальное значение n, для которого F (n) определено и превосходит 4242.
Решение
Для решения этой задачи мы используем рекурсивный метод вычисления функции F (n) и цикл для поиска нужного значения n.
Суть решения заключается в следующем:

  1. Функция F (n) вычисляется на основе заданных правил.
  2. Мы начинаем с n=1 и в цикле вычисляем значение F (n) для каждого n.
  3. Как только находим такое n, для которого F (n)>4242, мы выводим это значение n и останавливаем программу.

Подводный камень в этой задаче заключается в том, что для ускорения процесса поиска значение F (n) для чисел n, не делющихся на 6, установлено в -бесконечность. Это сделано для «обрезания» ненужных веток рекурсии и ускорения нахождения ответа.

Давайте разберем код построчно:
# Определение функции F(n) согласно заданным правилам
def f(n):
    # Если n <= 1, то F(n) = 0
    if n <= 1:
        return 0
    # Если n делится на 6, то F(n) = n + F(n / 6 - 2)
    elif n % 6 == 0:
        return n + f(n / 6 - 2)
    else:
        # Если n не делится на 6, то F(n) = n + F(n + 6)
        # Использование -бесконечности уместно, потому что это эффективно "срезает" ветки рекурсии для значений n, которые не делится на 6, ускоряя процесс поиска нужного значения n, при котором F(n) превосходит 4242.
        return -float('inf')

# Начальное значение n
n = 1

# Бесконечный цикл, который продолжается, пока не найдено значение n, для которого F(n) > 4242
while True:
    # Вычисляем значение F(n) для текущего n
    rez = f(n)
    # Если F(n) > 4242, выводим n и прерываем цикл
    if rez > 4242:
        print(n)
        break
    # Увеличиваем n на 1
    n += 1

Ответ: 4404
K. задача 17 сложная
Дан файл 17.txt, содержащий последовательность натуральных чисел, каждое из которых не превышает 100 000.

Определите количество троек чисел в этой последовательности, удовлетворяющих следующим условиям:

  1. Все три числа в тройке являются четырёхзначными.
  2. Сумма цифр каждого числа в тройке различна.
  3. Сумма всех трех чисел в тройке является палиндромом.
В ответе запишите количество найденных уникальных троек и максимальное значение суммы цифр среди всех чисел в этих тройках.

В данной задаче под тройкой подразумевается три идущих подряд элемента последовательности.

файл 17.txt можно открыть используя open ()
Решение
Для решения этой задачи мы используем следующую стратегию:
  1. Считываем все числа из файла в список.
  2. Определяем функции для проверки, является ли число палиндромом, и для вычисления суммы его цифр.
  3. Инициализируем переменные для подсчета количества троек чисел, удовлетворяющих условиям, и для хранения максимальной суммы цифр среди этих троек.
  4. Проходим по списку чисел, извлекая по три числа за раз, и проверяем, удовлетворяют ли они заданным условиям.
  5. Если условия выполняются, обновляем счетчики.
  6. В конце выводим полученные значения.

Подводный камень в этой задаче может заключаться в том, что нужно внимательно следить за тем, чтобы все числа в тройке были четырехзначными и чтобы суммы их цифр были различными. Также важно корректно проверить, является ли сумма чисел в тройке палиндромом.

Давайте разберем код построчно:
# Открываем файл и считываем все числа в список numbers
with open('17.txt', 'r') as f:
    numbers = list(map(int, f.read().split()))

# Функция для проверки, является ли число палиндромом
def is_palindrome(n):
    str_n = str(n)  # Преобразуем число в строку
    return str_n == str_n[::-1]  # Сравниваем строку и ее обратную версию

# Функция для вычисления суммы цифр числа
def digit_sum(n):
    return sum(int(digit) for digit in str(n))  # Суммируем цифры числа

# Инициализация переменных для подсчета троек и максимальной суммы цифр
count_triples = 0
max_digit_sum = 0

# Перебор троек чисел в списке
for i in range(len(numbers) - 2):
    triple = numbers[i:i+3]  # Извлекаем текущую тройку чисел
    
    # Проверяем, являются ли все числа в тройке четырехзначными
    if all(1000 <= num <= 9999 for num in triple):
        
        # Проверяем, различны ли суммы цифр для всех чисел в тройке
        unique_digit_sums = len(set(digit_sum(num) for num in triple))
        
        # Проверяем, является ли сумма всех чисел в тройке палиндромом
        total_sum_palindrome = is_palindrome(sum(triple))
        
        # Если все условия выполняются, обновляем счетчики
        if unique_digit_sums == 3 and total_sum_palindrome:
            count_triples += 1
            max_digit_sum = max(max_digit_sum, *(digit_sum(num) for num in triple))

# Выводим количество найденных троек и максимальную сумму цифр
print(count_triples, max_digit_sum)

Ответ: 61 35
L. задача 19 сложная
Алиса и Боб участвуют в игре с двумя кучами монет. Игра начинается с хода Алисы, и игроки ходят поочередно. В каждом ходе игрок имеет право добавить одну или две монеты в меньшую кучу. Количество монет в большей куче остается неизменным. Игра продолжается до тех пор, пока количество монет в обеих кучах не сравняется, и побеждает тот, кто делает последний ход. Оба игрока принимают только оптимальные решения.

Изначально в первой куче находится 15 монет, а во второй — S монет, где 1≤S≤30.

Необходимо определить максимальное значение S, при котором Алиса не может обеспечить себе победу за один ход, однако при любом ее ходе Боб способен выиграть уже своим первым ходом.
Решение
Для решения этой задачи мы используем рекурсивную функцию.
Эта функция определяет, может ли текущий игрок выиграть, исходя из состояния двух куч монет и количества оставшихся ходов.

  1. Функция сначала проверяет, равны ли обе кучи. Если да и количество оставшихся ходов четное, текущий игрок выигрывает.
  2. Если ходов нет, текущий игрок проигрывает.
  3. Затем функция анализирует возможные ходы. Если одна куча меньше другой, можно добавить 1 или 2 монеты к меньшей куче.
  4. На основе этих ходов функция рекурсивно вызывает себя, чтобы определить, можно ли выиграть на следующем ходу.

После этого мы запускаем цикл, чтобы найти максимальное значение S, при котором Алиса не может выиграть за один ход, но Боб может выиграть за два хода. Здесь S — это количество монет во второй куче, а bunch — это количество монет в первой куче.

Итак, суть этого решения заключается в использовании рекурсивной функции для моделирования игры и нахождения оптимального значения S, при котором Боб может обеспечить себе победу за один ход, а Алиса не может.

Давайте разберем код построчно:
# Функция f определяет, может ли текущий игрок выиграть, зная состояние куч и количество оставшихся ходов.
def f(a, b, m):
    if a == b: return m % 2 == 0  # Если кучи равны и ходов четное число, текущий игрок выигрывает.
    if m == 0: return 0  # Если ходов нет, текущий игрок проигрывает.
    # Выбираем ходы в зависимости от того, какая куча меньше.
    if a < b: h = [f(a + 1, b, m - 1), f(a + 2, b, m - 1)]
    else: h = [f(a, b + 1, m - 1), f(a, b + 2, m - 1)]
    # Если оставшихся ходов четное число, выигрыш возможен, если хотя бы один ход приводит к победе.
    # Если оставшихся ходов нечетное число, выигрыш возможен только если все ходы приводят к победе.
    return any(h) if (m - 1) % 2 == 0 else all(h)

# Изначальное количество монет в первой куче.
bunch = 15
# Максимально возможное количество монет во второй куче.
S = 31

# Ищем максимальное значение S, при котором Алиса не может выиграть за один ход, но Боб может выиграть за один ход.
print(max([s for s in range(1, S) if not f(bunch, s, 0) and f(bunch, s, 2)]))

Ответ: 18
M. задача 20 сложная
Алиса и Боб участвуют в игре с двумя кучами монет. Игра начинается с хода Алисы, и игроки ходят поочередно. В каждом ходе игрок имеет право добавить одну или две монеты в меньшую кучу. Количество монет в большей куче остается неизменным. Игра продолжается до тех пор, пока количество монет в обеих кучах не сравняется, и побеждает тот, кто делает последний ход. Оба игрока принимают только оптимальные решения.

Изначально в первой куче находится 15 монет, а во второй — S монет, где 1≤S≤30.

Определите два минимальных значения S, при которых Алисе доступна стратегия для выигрыша, удовлетворяя следующим критериям:

  • Алиса не имеет возможности выиграть за один ход;
  • Независимо от стратегии Боба, Алиса способна обеспечить себе победу на втором ходу.
Укажите обнаруженные значения в порядке возрастания.
Решение
Ход решения для данной задачи отличается от 19 тем, что сейчас мы фокусируемся на игре Алисы, а не Боба.
  1. Алиса не может выиграть за один ход. Это проверяется функцией f(bunch,s,1), которая должна вернуть False.
  2. Алиса может выиграть, если это её второй ход. Это проверяется функцией f(bunch,s,3), которая должна вернуть True.

Также для корректного вывода мы распаковываем список и берем два минимальных значения с помощью среза (они будут первые).

Давайте разберем код построчно:
# Функция f определяет, может ли текущий игрок выиграть, зная состояние куч и количество оставшихся ходов.
def f(a, b, m):
    if a == b: return m % 2 == 0  # Если кучи равны и ходов четное число, текущий игрок выигрывает.
    if m == 0: return 0  # Если ходов нет, текущий игрок проигрывает.
    # Выбираем ходы в зависимости от того, какая куча меньше.
    if a < b: h = [f(a + 1, b, m - 1), f(a + 2, b, m - 1)]
    else: h = [f(a, b + 1, m - 1), f(a, b + 2, m - 1)]
    # Если оставшихся ходов четное число, выигрыш возможен, если хотя бы один ход приводит к победе.
    # Если оставшихся ходов нечетное число, выигрыш возможен только если все ходы приводят к победе.
    return any(h) if (m - 1) % 2 == 0 else all(h)

# Изначальное количество монет в первой куче.
bunch = 15
# Максимально возможное количество монет во второй куче.
S = 31

# Ищем два минимальных значения S, при которых Алиса не может выиграть за один ход, но может выиграть за два хода.
print(*[s for s in range(1, S) if not f(bunch, s, 1) and f(bunch, s, 3)][:2])

Ответ: 10 11
N. задача 21 сложная
Алиса и Боб участвуют в игре с двумя кучами монет. Игра начинается с хода Алисы, и игроки ходят поочередно. В каждом ходе игрок имеет право добавить одну или две монеты в меньшую кучу. Количество монет в большей куче остается неизменным. Игра продолжается до тех пор, пока количество монет в обеих кучах не сравняется, и побеждает тот, кто делает последний ход. Оба игрока принимают только оптимальные решения.

Изначально в первой куче находится 15 монет, а во второй — S монет, где 1≤S≤30.

Определите два таких значения S, для которых соблюдаются следующие критерии:

  • Боб обладает стратегией, позволяющей ему победить на первом или втором ходу, независимо от действий Алисы;
  • Боб не имеет стратегии, гарантирующей ему победу сразу на первом ходу
Укажите обнаруженные значения в порядке возрастания.
Решение
Ход решения для данной задачи отличается от задачи 20 тем, что:
  1. Боб не может гарантированно выиграть своим первым ходом. Это проверяется функцией f(bunch, s, 2), которая должна вернуть False.
  2. Боб может выиграть, если у него будет два хода. Это проверяется функцией f(bunch, s, 4), которая должна вернуть True.
В остальном решение идентичное и подробно расписано в 19 задаче.
# Функция f определяет, может ли текущий игрок выиграть, зная состояние куч и количество оставшихся ходов.
def f(a, b, m):
    if a == b: return m % 2 == 0  # Если кучи равны и ходов четное число, текущий игрок выигрывает.
    if m == 0: return 0  # Если ходов нет, текущий игрок проигрывает.
    # Выбираем ходы в зависимости от того, какая куча меньше.
    if a < b: h = [f(a + 1, b, m - 1), f(a + 2, b, m - 1)]
    else: h = [f(a, b + 1, m - 1), f(a, b + 2, m - 1)]
    # Если оставшихся ходов четное число, выигрыш возможен, если хотя бы один ход приводит к победе.
    # Если оставшихся ходов нечетное число, выигрыш возможен только если все ходы приводят к победе.
    return any(h) if (m - 1) % 2 == 0 else all(h)

# Изначальное количество монет в первой куче
bunch = 15
# Максимально возможное количество монет во второй куче
S = 31

# Находим два значения S, при которых Боб может выиграть на первом или втором ходу, но не может выиграть сразу на первом ходу.
print(*[s for s in range(1, S) if not f(bunch, s, 2) and f(bunch, s, 4)])

Ответ: 9 21
O. задача 22 сложная
В файле 22.txt содержится информация о совокупности N вычислительных процессов, которые могут выполняться параллельно или последовательно. Будем говорить, что процесс B зависит от процесса A, если для выполнения процесса B необходимы результаты выполнения процесса A. В этом случае процессы могут выполняться только последовательно.

Информация о процессах представлена в виде txt файла.

В первом столбце указан идентификатор процесса (ID), во втором столбце — время его выполнения в миллисекундах, в третьем столбце перечислены с разделителем «;» ID процессов, от которых зависит данный процесс. Если процесс является независимым, то указано значение 0.

Вот первые строки файла 22.txt:
1 206 0
2 101 0
3 258 2
4 264 3;2;1
5 172 2;4
файл 22.txt можно открыть используя open()
Определите минимальное время, через которое завершится выполнение всей совокупности процессов, при условии, что все независимые друг от друга процессы могут выполняться параллельно.
Решение
Для решения этой задачи мы используем словарь для хранения минимального времени выполнения каждого процесса.
Изначально в этом словаре есть только начальный процесс с временем выполнения равным нулю.

Мы также создаём список, в который считываем все данные о процессах и их зависимостях.

Перебираем процессы до тех пор, пока не найдены минимальные времена выполнения для всех процессов. В каждом проходе этого цикла мы просматриваем все процессы и проверяем, известно ли нам уже минимальное время выполнения для всех их зависимостей. Если известно, мы вычисляем и сохраняем минимальное время выполнения для текущего процесса как сумму его собственного времени выполнения и максимального из минимальных времен выполнения его зависимостей.

В конце программы мы выводим максимальное из найденных минимальных времен выполнения.

Давайте разберем код построчно:
d = {'0': 0}  # Словарь для хранения минимального времени выполнения для каждого процесса
data = []  # Список для хранения информации о каждом процессе

# Чтение данных из файла и преобразование их в удобный для работы формат
for s in open('22.txt'):
    data.append(s.replace(';', ' ').split())

# Цикл, который будет выполняться до тех пор, пока для всех процессов не будет найдено минимальное время выполнения
while len(d) != len(data) + 1:
    for s in data:
        # Проверка, известно ли минимальное время выполнения для всех зависимостей текущего процесса
        if all(sub in d for sub in s[2:]):
            # Вычисление и сохранение минимального времени выполнения для текущего процесса
            d[s[0]] = int(s[1]) + max(d[sub] for sub in s[2:])

# Вывод максимального значения среди всех минимальных времен выполнения процессов
print(max(d.values()))

Ответ: 11605
P. задача 23 сложная
Исполнитель преобразует число на экране. У исполнителя есть четыре команды, которые обозначены латинскими буквами:

  1. Прибавить 2
  2. Умножить на 3
  3. Возвести в куб

Программа для исполнителя — это последовательность команд.

Необходимо найти количество существующих программ, для которых при исходном числе 3 результатом является число 125, при этом траектория вычислений не содержит числа 27 и содержит не более 15 команд.
Траектория вычислений программы — это последовательность результатов выполнения всех команд программы. Например, для программы CBA при исходном числе 3 траектория состоит из чисел 27, 54, 56.
Решение
Для решения этой задачи мы используем рекурсивную функцию.
Эта функция принимает четыре параметра: текущее число x, целевое число y, количество уже сделанных шагов и максимально допустимое количество шагов. Функция возвращает количество путей, которыми можно преобразовать x в y, не превышая заданное количество шагов и не используя число 27.

  1. Если текущее число x равно 27, мы сразу возвращаем 0, потому что 27 нам использовать нельзя.
  2. Если x больше или равно y, мы проверяем, не превышено ли количество шагов. Если всё в порядке, возвращаем 1, иначе 0.
  3. Если количество сделанных шагов равно максимально допустимому, возвращаем 0.
  4. В противном случае, мы рекурсивно вызываем функцию для трех возможных операций: x+2, x×3 и x^3, увеличивая при этом количество шагов на 1.
  5. Суммируем количество путей, полученных из рекурсивных вызовов, и это будет ответом функции.

На выходе функция даст нам количество способов преобразовать число 3 в 125, соблюдая заданные условия.

Давайте разберем код построчно:
# Функция f рекурсивно ищет количество путей для преобразования числа x в y, не превышая max_steps шагов и избегая числа 27.
def f(x, y, steps, max_steps):
    if x == 27: return 0  # Исключаем траектории, включающие число 27
    if x >= y: return x == y and steps <= max_steps  # Если достигли или превысили y, проверяем, не превышено ли количество шагов
    if steps >= max_steps: return 0  # Если превышено максимальное количество шагов, возвращаем 0
    # Рекурсивно вызываем функцию для всех трех возможных операций: прибавления 2, умножения на 3 и возведения в куб.
    return f(x + 2, y, steps + 1, max_steps) + f(x * 3, y, steps + 1, max_steps) + f(x ** 3, y, steps + 1, max_steps)

# Ищем количество программ, которые преобразуют число 3 в 125, не превышая 15 шагов и избегая числа 27.
print(f(3, 125, 0, 15))
Ответ: 12
Q. задача 24 сложная
Текстовый файл 24.txt состоит из символов A, B, C, D, E.
Определите в прилагаемом файле минимальное количество идущих подряд символов (длину непрерывной подпоследовательности), среди которых символ E встречается ровно 100 раз.
Решение
Для решения этой задачи мы используем подход «двух указателей» для определения подпоследовательности в строке.
Наша цель — найти самую короткую подпоследовательность, содержащую ровно 100 символов 'E'.

  1. В начале работы программы два указателя (start и end) установлены на начало строки. Счетчик count_E для подсчета количества символов 'E' в текущей подпоследовательности инициализируется нулем.
  2. Указатель end двигается вправо по строке. Каждый раз, когда он натыкается на символ 'E', счетчик count_E увеличивается на 1.
  3. Как только count_E достигает 100, начинается внутренний цикл, в котором указатель start двигается вправо до тех пор, пока count_E не станет меньше 100. Это делается для того, чтобы найти минимальную длину подпоследовательности с 100 символами 'E'.
  4. В процессе этого движения, если под указателем start находится символ 'E', счетчик count_E уменьшается на 1.
  5. После того как count_E становится меньше 100, внутренний цикл завершается, и процесс повторяется с обновленным значением end.

На выходе у нас будет минимальная длина подпоследовательности, содержащей ровно 100 символов 'E', или 0, если таковой не существует.

Давайте разберем код построчно:
with open("24.txt", "r") as file:
    content = file.read()

# Инициализация переменных
start = 0  # Начальный указатель
end = 0  # Конечный указатель
count_E = 0  # Счетчик символов 'E'
min_length = float('inf')  # Минимальная длина подпоследовательности

# Перемещение указателя end и поиск минимальной длины подпоследовательности
while end < len(content):
    # Увеличиваем счетчик, если текущий символ - 'E'
    if content[end] == 'E':
        count_E += 1
    
    # Перемещаем указатель start, если счетчик достиг 100
    while count_E == 100:
        # Обновляем минимальную длину
        min_length = min(min_length, end - start + 1)
        # Уменьшаем счетчик, если символ под указателем start - 'E'
        if content[start] == 'E':
            count_E -= 1
        # Перемещаем указатель start вправо
        start += 1
    
    # Перемещаем указатель end вправо
    end += 1

min_length if min_length != float('inf') else 0
print(min_length)
Ответ: 353
R. задача 25 сложная
Назовём маской числа последовательность цифр, в которой также могут встречаться следующие символы:

  • символ «?» означает ровно одну произвольную цифру;
  • символ «*» означает любую последовательность цифр произвольной длины; в том числе «*» может задавать и пустую последовательность.

Например, маске 123*4?5 соответствуют числа 123405 и 12300405.

Пусть М(k) — сумма минимального и максимального натуральных делителей целого числа k, не считая единицы и самого числа. Если таких делителей у числа нет, то считаем значение M(k) равным нулю.

Напишите программу, которая находит все такие числа k, что:

  1. k не превосходит 108.
  2. Значение M (k) не равно 0 и делится на 117.
  3. Десятичная запись числа k удовлетворяет маске 51*2?34
Выведите все найденные значения k в порядке возрастания. В одной строке выводите число k, затем, через пробел, значение M (k).
Решение
Для решения этой задачи мы используем два основных этапа: сопоставление строки с шаблоном и поиск делителей числа.
  1. Сначала мы импортируем функцию fnmatch для сопоставления строк с шаблоном. Эта функция позволяет нам легко проверить, соответствует ли число шаблону '51*2?34'.
  2. Затем у нас есть функция find_divisors, которая принимает число n и возвращает список его делителей. Для этого мы перебираем числа от 2 до корня из n​ и проверяем, являются ли они делителями n.
  3. В главном цикле мы перебираем числа от 0 до 10^8. Для каждого числа мы проверяем, соответствует ли оно шаблону '51*2?34' с помощью функции fnmatch.
  4. Если число соответствует шаблону, мы находим его делители с помощью функции find_divisors.
  5. После этого мы проверяем два условия: есть ли у числа делители и делится ли сумма его минимального и максимального делителя на 117. Если оба условия выполняются, мы выводим число и сумму его минимального и максимального делителя.

Таким образом, этот код находит числа, соответствующие определенному шаблону, находит их делители и проверяет, удовлетворяют ли они заданным условиям.

Давайте разберем код построчно:
# Импорт функции fnmatch для сопоставления строки с шаблоном
from fnmatch import fnmatch

# Функция для нахождения делителей числа n
def find_divisors(n):
    # Инициализация множества для хранения делителей
    divisors = set()
    
    # Цикл для перебора возможных делителей от 2 до корня из n
    for i in range(2, int(n**0.5) + 1):
        # Проверка, является ли i делителем n
        if n % i == 0:
            # Добавление i и n/i в множество делителей
            divisors.add(i)
            divisors.add(n // i)
            
    # Возвращение отсортированного списка делителей
    return sorted(divisors)

# Главный цикл: перебор чисел от 0 до 10^8
for n in range(0, 10**8 + 1):
    # Сопоставление числа n с маской 51*2?34
    if fnmatch(str(n), '51*2?34'):
        # Вызов функции для нахождения делителей числа n
        divisors = find_divisors(n)
        
        # Проверка условий: есть делители и их сумма делится на 117
        if divisors and (divisors[0] + divisors[-1]) % 117 == 0:
            # Вывод числа n и суммы его минимального и максимального делителя
            print(n, divisors[0] + divisors[-1])

Ответ:
5102834 2551419
51072134 25536069
51142334 25571169
51212534 25606269
51282734 25641369
51352934 25676469
51622034 25811019
51692234 25846119
51762434 25881219
51832634 25916319
51902834 25951419
S. задача 26 сложная
Входной файл 26.txt содержит сведения о заявках на проведение мероприятий в конференц-зале. В каждой заявке указаны время начала и время окончания мероприятия (в минутах от начала суток). В первой строчке записано количество мероприятий.
Начало файла 26.txt
20000
280 932
284 681
359 460
165 1031
Если время начала одного мероприятия меньше времени окончания другого, то провести можно только одно из них.

Если время окончания одного мероприятия совпадает со временем начала другого, то провести можно оба.

Определите, какое максимальное количество мероприятий можно провести в конференц-зале и какое самое позднее время, когда может начаться первое мероприятие, при этом будет проведено максимально возможное число мероприятий.
В ответе укажите максимальное количество мероприятий и самое позднее время начала первого мероприятия через пробел.
Решение
Для решения этой задачи мы используем следующий подход:
  1. Сначала мы считываем данные из файла, в котором указаны мероприятия и их времена начала и окончания.
  2. Затем мы сортируем все мероприятия по времени их окончания. Это поможет нам быстрее определить, какие мероприятия можно провести.
  3. После этого у нас есть функция max_events, которая определяет максимальное количество мероприятий, которое можно провести. Она проходит по всем мероприятиям и считает, сколько из них не пересекаются по времени.
  4. Далее, используя эту функцию, мы определяем максимальное количество мероприятий, которое можно провести в конференц-зале.
  5. После того, как мы знаем максимальное количество мероприятий, мы ищем самое позднее время начала первого мероприятия, при котором можно провести максимальное количество мероприятий.
  6. В конце мы выводим ответ: максимальное количество мероприятий и самое позднее время начала первого мероприятия.

Этот подход позволяет нам эффективно решить задачу, используя только один проход по списку мероприятий для каждого этапа.

Давайте разберем код построчно:
# Считывание данных из файла
# Открываем файл 26.txt для чтения
with open('26.txt', 'r') as f:
    # Считываем первую строку, в которой указано количество мероприятий, и преобразуем её в целое число
    N = int(f.readline().strip())
    # Считываем оставшиеся строки, каждая из которых содержит два числа, разделенных пробелом, и преобразуем их в кортежи
    events_data = [tuple(map(int, line.split())) for line in f.readlines()]

# Сортировка заявок по времени окончания
# Сортируем список мероприятий по времени их окончания
sorted_events = sorted(events_data, key=lambda x: x[1])

# Функция для определения максимального количества мероприятий, которые можно провести
def max_events(events):
    count = 0  # Счетчик для количества мероприятий
    last_end_time = -1  # Время окончания последнего мероприятия
    # Проходимся по каждому мероприятию в отсортированном списке
    for start, end in events:
        # Проверяем, можно ли провести текущее мероприятие
        if start >= last_end_time:
            count += 1  # Увеличиваем счетчик мероприятий
            last_end_time = end  # Обновляем время окончания последнего мероприятия
    return count  # Возвращаем количество мероприятий

# Вызываем функцию для получения максимального количества мероприятий
max_count = max_events(sorted_events)

# Определение самого позднего времени начала первого мероприятия
latest_start_time = None  # Инициализация переменной для хранения времени

# Проходимся по списку мероприятий в обратном порядке
for start, _ in reversed(sorted_events):
    # Фильтруем мероприятия, которые начинаются не раньше текущего
    current_events = [(s, e) for s, e in sorted_events if s >= start]
    # Проверяем, совпадает ли максимальное количество мероприятий
    if max_events(current_events) == max_count:
        latest_start_time = start  # Сохраняем время начала
        break  # Выходим из цикла

# Выводим результат
print(max_count, latest_start_time)

Ответ: 66 18
T. задача 27_A сложная
На каждом километре автомагистрали, начиная с первого, расположены пункты питания. Известна суточная потребность каждого пункта питания в количестве готовых обедов. По правилам готовую еду нельзя перевозить на расстояние, превышающее М км.

Для транспортировки используются термоконтейнеры вместимостью не более 6 готовых обедов. Каждый термоконтейнер используется для доставки только в один пункт питания, при этом в каждый пункт питания может быть доставлено не более одного термоконтейнера с неполной загрузкой. Компания-производитель расположила в двух пунктах питания два цеха для производства готовых обедов так, что из этих цехов в пункты питания ежедневно отправляется максимальное количество термоконтейнеров с готовыми обедами.

Определите необходимое суммарное количество термоконтейнеров для ежедневной перевозки готовых обедов в пункты питания из двух цехов.
Входные данные
Дан входной файл 27_A.txt, каждый из которых в первой строке содержит два числа N и M (1 ≤ N ≤ 10 000 000, 1 ≤ M ≤ 10 000 000) количество пунктов и максимальное расстояние, на которое разрешается перевозить комплект готового питания. В каждой из следующих N строк находится одно число: суточная потребность соответствующего пункта в комплектах готового питания. Информация о пунктах дана в порядке их расположения вдоль автомагистрали.

В ответе укажите значение искомой величины для файла 27_A.txt.

Типовой пример организации данных во входном файле:
8 1
6
1
8
4
3
5
2
7
При таких исходных данных и вместимости термоконтейнера 5 готовых обедов выгодно открыть производственные цеха в пунктах питания на втором и седьмом километрах дороги, куда доставляются 1 и 2 готовых обеда соответственно. В этом случае количество термоконтейнеров составит: 2 + 1 + 2 + 1 + 1 + 2

Типовой пример имеет иллюстративный характер. Для выполнения задания используйте данные из файла 27_A.txt.

Решение
Для решения этой задачи мы используем метод полного перебора.
Этот метод заключается в том, чтобы просмотреть все возможные варианты расположения двух цехов и выбрать такое их расположение, при котором будет доставлено максимальное количество готовых обедов.

Сначала нам нужно преобразовать данные о потребностях каждого пункта питания в количество необходимых термоконтейнеров, округляя в большую сторону, так как даже для одного обеда потребуется целый термоконтейнер.

Затем мы начинаем перебор возможных позиций для первого цеха. Позиции выбираются так, чтобы они не выходили за пределы дистанции, доступной для доставки (М километров). Для каждой возможной позиции первого цеха мы также перебираем возможные позиции для второго цеха, учитывая, что между ними должно быть расстояние не меньше чем М километров, чтобы их зоны обслуживания не пересекались.

Для каждой пары позиций цехов мы подсчитываем общее количество термоконтейнеров, которое они могут доставить, учитывая зону обслуживания каждого цеха и требования к доставке. В процессе перебора мы сохраняем максимальное найденное значение.

По завершении перебора мы получаем максимальное количество термоконтейнеров, которое можно доставить при оптимальном расположении двух цехов.

Давайте разберем код построчно:
# решение полным перебором
from math import ceil

f_name = '27_A.txt'
with open(f_name) as f:
    n, m, *nums = [int(x) for x in f.read().split()]
nums = [ceil(x / 6) for x in nums]

total_max = 0
# у первой позиции возьмём диапазон n - m, потому что правые m чисел возьмёт
# второй диапазон
for pos1 in range(n - m):
    # второй начнём собирать с pos1 + m + m, чтобы диапазоны не пересекались
    # это стоит нарисовать для полного понимания
    for pos2 in range(pos1 + m + m + 1, n - m):
        total = 0
        # тут нет смысла перебирать все числа. достаточно перебрать те, что
        # входят в диапазон
        for i in range(max(0, pos1 - m), min(pos1 + m + 1, n)):
            total += nums[i]
        for i in range(max(0, pos2 - m), min(pos2 + m + 1, n)):
            total += nums[i]
        total_max = max(total, total_max)
print(total_max)
Ответ: 11754
U. задача 27_B сложная
На каждом километре автомагистрали, начиная с первого, расположены пункты питания. Известна суточная потребность каждого пункта питания в количестве готовых обедов. По правилам готовую еду нельзя перевозить на расстояние, превышающее М км.

Для транспортировки используются термоконтейнеры вместимостью не более 6 готовых обедов. Каждый термоконтейнер используется для доставки только в один пункт питания, при этом в каждый пункт питания может быть доставлено не более одного термоконтейнера с неполной загрузкой. Компания-производитель расположила в двух пунктах питания два цеха для производства готовых обедов так, что из этих цехов в пункты питания ежедневно отправляется максимальное количество термоконтейнеров с готовыми обедами.

Определите необходимое суммарное количество термоконтейнеров для ежедневной перевозки готовых обедов в пункты питания из двух цехов.
Входные данные
Дан входной файл 27_B.txt, каждый из которых в первой строке содержит два числа N и M (1 ≤ N ≤ 10 000 000, 1 ≤ M ≤ 10 000 000) количество пунктов и максимальное расстояние, на которое разрешается перевозить комплект готового питания. В каждой из следующих N строк находится одно число: суточная потребность соответствующего пункта в комплектах готового питания. Информация о пунктах дана в порядке их расположения вдоль автомагистрали.

В ответе укажите значение искомой величины для файла 27_B.txt.

Типовой пример организации данных во входном файле:
8 1
6
1
8
4
3
5
2
7
При таких исходных данных и вместимости термоконтейнера 5 готовых обедов выгодно открыть производственные цеха в пунктах питания на втором и седьмом километрах дороги, куда доставляются 1 и 2 готовых обеда соответственно. В этом случае количество термоконтейнеров составит: 2 + 1 + 2 + 1 + 1 + 2
Предупреждение:
для обработки файла 27_B.txt не следует использовать переборный алгоритм, вычисляющий сумму для всех возможных вариантов, поскольку написанная по такому алгоритму программа будет выполняться слишком долго.
Решение
Для решения задачи по файлу Б мы подходим к проблеме с точки зрения каждого отдельного пункта питания и определяем, сколько термоконтейнеров мы можем доставить в каждый из них.
Мы делаем это, считая сумму возможных термоконтейнеров для доставки в каждый пункт в определенном диапазоне.

Сначала рассмотрим пример: чтобы понять, сколько контейнеров мы можем доставить в пункт с номером m, мы считаем сумму термоконтейнеров, которые могут быть доставлены в диапазоне от пункта 0 до пункта 2m, потому что это максимальное расстояние доставки из цеха в пункт m и обратно. Для пункта m+1, диапазон будет от 1 до 2m+1.

Теперь, когда у нас есть эти суммы для каждого пункта, мы ищем два диапазона, которые не пересекаются и дают максимальную сумму термоконтейнеров. Это как будто мы ищем две лучшие позиции для наших цехов, чтобы максимизировать количество доставленной еды.

Мы начинаем с начальной позиции, где оба диапазона располагаются один за другим. Затем мы начинаем сдвигать один из диапазонов (например, синий) вправо по одному шагу за раз и проверяем, дает ли эта новая комбинация большее количество контейнеров. Если да, мы обновляем наш максимум. После каждого сдвига синего диапазона мы также проверяем, можем ли мы переместить другой диапазон (черный) так, чтобы использовать освободившееся пространство. Это может привести к еще большему количеству доставляемых термоконтейнеров.

Таким образом, мы перебираем все возможные комбинации, пока не найдем ту, которая дает максимальное количество термоконтейнеров, которые могут быть доставлены с учетом всех ограничений. Это и будет нашим окончательным ответом на задачу.

Давайте разберем код построчно:
# оптимальное решение
from math import ceil

f_name = '27_B.txt'
with open(f_name) as f:
    n, m, *nums = [int(x) for x in f.read().split()]
nums = [ceil(x / 6) for x in nums]

# мы не считаем значения от 0 до m-1 и от n-m-1 до n-1, потому что там точно
# будет меньше
totals = [sum(nums[0:2*m+1])]
for i in range(m, n - m - 1):
    total = totals[-1] - nums[i - m] + nums[i + m + 1]
    totals.append(total)

# наибольший ответ
ans_max = 0
# сумма левого диапазона
left = totals[0]
# перебираем правый диапазон
for i in range(m + m + 1, len(totals)):
    # выделяем правый диапазон
    right = totals[i]
    # обновляем максимум
    if left + right > ans_max:
        ans_max = left + right
    # сдвигаем левый диапазон, если он более выгодный
    if totals[i - 2 * m] > left:
        left = totals[i - 2 * m]
print(ans_max)
Ответ: 148974
Fri Feb 09 2024 12:48:03 GMT+0300 (Moscow Standard Time)