Что проверяет задание
В файле дана последовательность целых чисел. Нужно посчитать пары, тройки или элементы, удовлетворяющие условию, и часто дополнительно взять сумму, максимум или минимум среди подходящих.
Определения
Последовательность, числа в том порядке, в котором они записаны в файле. Порядок важен, если речь о соседстве.
Соседние элементы, стоящие рядом в последовательности: индексы i и i + 1.
Пара различных элементов, два числа, не обязательно соседние. Тогда перебирают все неупорядоченные или упорядоченные пары, как сказано в условии.
Кратность / делимость, одно число делится на другое или на заданную константу. Для пары часто смотрят сумму, произведение или хотя бы один элемент.
Контрольное значение, величина, вычисленная по всей последовательности заранее: например, минимальный кратный 17 элемент. Условие на пару тогда сравнивает пару с этим глобальным значением.
Диапазон, ограничение «оба числа из отрезка» или «хотя бы одно из отрезка».
Количество и характеристика, типичный двойной ответ: сколько объектов и, например, максимальная сумма среди них.
Соседние и несоседние
Это разные задачи. Для соседних достаточно одного прохода по файлу. Для произвольных пар полный двойной цикл по большому файлу тяжёл, поэтому условие обычно позволяет опереться на сортировку, подсчёт по остаткам или на предварительно собранные экстремумы.
Остаток по модулю m, ключ к делимости суммы: сумма делится на m, если сумма остатков делится на m.
Общий алгоритм решения
- Прочитать, какой объект считают: элемент, соседняя пара, произвольная пара, тройка.
- Выписать все ограничения и какую вторую величину нужно сообщить.
- Сначала один раз пройти последовательность, если нужны глобальные контрольные значения.
- Вторым проходом (или тем же, если возможно) отобрать подходящие объекты.
- Обновить счётчик и текущий максимум/минимум.
- Проверить, не считают ли одну и ту же пару дважды и не сравнивают ли элемент сам с собой.
Программа построчно
В задании 17 в файле записана последовательность чисел. Нужно перебрать пары соседних элементов, посчитать подходящие и найти наибольшую (или наименьшую) сумму среди них.
Разберём программу на условии:
В файле 17.txt содержится последовательность натуральных чисел. Под парой подразумевается два идущих подряд элемента. Определите количество пар, в которых оба числа нечётные, а их сумма больше максимального чётного элемента последовательности. В ответе запишите количество пар, затем максимальную из сумм.
a = list(map(int, open("17.txt").read().split()))
evens = [x for x in a if x % 2 == 0]
max_even = max(evens)
count = 0
best = -10 ** 18
for i in range(len(a) - 1):
x, y = a[i], a[i + 1]
if x % 2 == 1 and y % 2 == 1 and x + y > max_even:
count += 1
best = max(best, x + y)
print(count, best)
a = list(map(int, open("17.txt").read().split())) - читаем весь файл и превращаем его в список чисел. Подробно - в разделе «Чтение последовательности».
evens = [x for x in a if x % 2 == 0] и max_even = max(evens) - «максимальный чётный элемент последовательности»: сначала выбираем все чётные числа, потом наибольшее из них. Такие величины считают до перебора пар. Подробно - в разделе «Величины по всей последовательности».
count = 0 - счётчик подходящих пар; best = -10 ** 18 - наибольшая сумма; начальное значение заведомо меньше любой суммы.
for i in range(len(a) - 1): / x, y = a[i], a[i + 1] - перебираем все пары соседних элементов. Подробно - в разделе «Перебор соседних пар».
if … and … and …: - условие из задачи, каждая часть через and. Подробно - в разделе «Условия на пару».
count += 1 / best = max(best, x + y) - пара подходит: увеличиваем счётчик и обновляем наибольшую сумму. Подробно - в разделе «Счётчик и экстремум».
print(count, best) - два числа через пробел, как требует ответ.
Чтение последовательности
a = list(map(int, open("17.txt").read().split()))
По шагам:
open("17.txt")- открываем файл (он лежит рядом с программой);.read()- читаем весь файл одной строкой:'12\n35\n40\n…';.split()- режем по пробелам и переводам строк:['12', '35', '40', …]. Неважно, записаны числа по одному в строке или через пробел;map(int, …)- каждый кусок превращаем в число;list(…)- собираем в списокa. К элементам обращаются по номеру:a[0]- первый,a[1]- второй.
Величины по всей последовательности
Условие часто сравнивает пару с величиной, посчитанной по всей последовательности. Её находят один раз, до цикла:
- среднее арифметическое:
avg = sum(a) / len(a)- сумма всех элементов, делённая на их количество; - максимальный элемент:
max(a), минимальный:min(a); - максимальный чётный элемент:
max([x for x in a if x % 2 == 0])- сначала список чётных, потом наибольший; - минимальный двузначный:
min([x for x in a if 10 <= x <= 99]); - максимальный элемент, оканчивающийся на 3:
max([x for x in a if x % 10 == 3]).
Запись [x for x in a if условие] - список-фильтр: в него попадают только элементы, для которых условие истинно.
Если посчитать такую величину внутри цикла, программа будет пересчитывать её для каждой пары - это очень медленно.
Перебор соседних пар
for i in range(len(a) - 1):
x, y = a[i], a[i + 1]
i- номер первого элемента пары,a[i + 1]- следующий за ним;- у последнего элемента нет следующего, поэтому
iидёт доlen(a) - 2включительно:range(len(a) - 1). Если написатьrange(len(a)), на последнем шагеa[i + 1]выйдет за границу списка - ошибкаIndexError; x, y = a[i], a[i + 1]- даём элементам пары короткие имена, чтобы условие читалось легче.
Для троек идущих подряд элементов - так же, но до len(a) - 2:
for i in range(len(a) - 2):
x, y, z = a[i], a[i + 1], a[i + 2]
Условия на пару
Каждую фразу условия записывают отдельной проверкой и соединяют через and:
- «оба числа нечётные» →
x % 2 == 1 and y % 2 == 1; - «элементы имеют разную чётность» →
(x + y) % 2 != 0: сумма чётного и нечётного нечётна; - «хотя бы одно число оканчивается на 3» →
x % 10 == 3 or y % 10 == 3; для отрицательных чисел последнюю цифру берут по модулю:abs(x) % 10 == 3; - «только один из элементов двузначный» →
(10 <= x <= 99) != (10 <= y <= 99): свойство есть ровно у одного - значения сравнения разные; - «сумма кратна 9» →
(x + y) % 9 == 0; - «произведение кратно 5» →
(x * y) % 5 == 0; - «сумма меньше среднего арифметического» →
x + y < avg; - для троек «ровно два числа трёхзначные» →
sum(1 for t in (x, y, z) if 100 <= t <= 999) == 2: перебираем три числа и считаем те, что подходят.
Скобки вокруг «внутренних» частей ((x + y) % 9) обязательны: без них % применится только к y.
Счётчик и экстремум
count = 0
best = -10 ** 18
...
count += 1
best = max(best, x + y)
print(count, best)
count += 1- увеличиваем счётчик для каждой подходящей пары;best = max(best, x + y)- если сумма текущей пары больше запомненной, запоминаем её;- начальное
best = -10 ** 18(минус десять в восемнадцатой степени) меньше любой возможной суммы, поэтому первая же подходящая пара его заменит; - для минимальной суммы - наоборот:
best = 10 ** 18иbest = min(best, x + y).
