ЕГЭ · Информатика · Массивы и строки
Задание 8: комбинаторика слов и чисел
Считать количество и номера слов в алфавитном списке — без перебора всех вариантов.
🎯 ЕГЭ информатика: этот урок закрывает задание(я) 8.
- ⚠Считают перестановки вместо размещений с повторениями (Nk)
- ⚠Не учитывают дополнительное условие (начинается с…, не содержит…) — забывают вычесть лишние
Задание 8: комбинаторика слов
Определение
Число и номер слова — слов длины L из алфавита размера m всего mL. Слова упорядочены как числа в системе с основанием m; номер слова = (значение как m-ичного числа) + 1
Для подсчёта слов с ограничениями (ровно две буквы О, не начинается с А) удобнее перебрать все слова через itertools.product — при малых L быстро и без ошибок. Заведи счётчик номера (нумерация с 1) и проверяй условия по строке word.
Разбор примера
Подсчёт слов через перебор
Сколько трёхбуквенных слов из букв {А,Б,В} содержат ровно одну букву А.
Показать решение по шагам
- 1.
from itertools import product alph = 'АБВ' count = 0 for w in product(alph, repeat=3): word = ''.join(w) if word.count('А') == 1: count += 1 print(count) # 12
Ответ: Прямой перебор всех 27 слов даёт 12
Два вопроса, которые задаёт линия 8
Задание 8 — про подсчёт слов и чисел, и вопросов в нём всего два.
Сколько слов удовлетворяют условию. Формулировка из банка: «Все слова, состоящие из 6 букв, в которых могут использоваться только буквы А Д К Л О, записаны в некотором порядке. Буквы в слове могут повторяться. Сколько существует таких слов, в которых буква Л встречается ровно 2 раза?» Условие меняется — «ровно одна цифра 3», «не содержит буквы Ь», «нет двух одинаковых подряд», «цифра 0 не стоит рядом с цифрой 3» — но вопрос один: посчитать.
Какой номер у слова или какое слово под номером. «Все пятибуквенные слова из букв М А С Л О записаны в алфавитном порядке и пронумерованы начиная с 1. Под каким номером идёт первое слово, которое…» Здесь работает связь слов с числами в позиционной системе счисления, и о ней вторая половина урока.
Важная общая деталь: буквы могут повторяться. Это сказано в условии прямым текстом и означает, что речь не о перестановках и не о сочетаниях, а о размещениях с повторениями. Слов длины L из алфавита размера m ровно mL, и никакие факториалы здесь не нужны.
И вторая: слов в линии 8 всегда немного. Пять букв, длина шесть — это 15 625 вариантов; шесть букв, длина шесть — 46 656. Компьютер перебирает их за доли секунды. Поэтому главный инструмент линии 8 — не формула, а перебор, и формулы нужны скорее для проверки.
Правило произведения: откуда берётся mL
Почему слов длины L из алфавита размера m ровно mL?
Строим слово по одной букве. На первую позицию можно поставить любую из m букв. Независимо от того, что там оказалось, на вторую позицию снова годятся все m букв — повторения разрешены. И так далее. Число способов перемножается: m · m · … · m, L раз.
Это правило произведения: если действие состоит из независимых шагов и на каждом шаге есть своё число вариантов, общее число исходов равно произведению.
Отсюда же считаются варианты с ограничениями на отдельные позиции. «Пятизначное число в четверичной системе» — это слово длины 5 из цифр 0, 1, 2, 3, но первая цифра не может быть нулём, иначе число не пятизначное. Значит, вариантов 3 · 4 · 4 · 4 · 4 = 768, а не 4⁵ = 1024.
«Слово не содержит буквы Ь» при алфавите из шести букв — это слово из оставшихся пяти букв: 5L вместо 6L.
А вот условия вида «ровно две буквы Л» или «нет двух одинаковых подряд» через простое произведение не считаются: позиции перестают быть независимыми. Для них есть отдельные приёмы — и есть перебор, который работает всегда.
Разбор примера
Комбинаторный счёт: ровно две буквы Л в слове из шести
Все слова из 6 букв, в которых используются только буквы А, Д, К, Л, О (буквы могут повторяться). Сколько таких слов, в которых буква Л встречается ровно 2 раза?
Показать решение по шагам
- 1. Шаг 1. Разделим задачу на два независимых выбора: где стоят буквы Л и что стоит на остальных местах.
- 2. Шаг 2. Выбор позиций. Из шести мест надо выбрать два под букву Л. Порядок здесь не важен — обе буквы одинаковы, — значит это сочетания: C(6,2) = 6 · 5 / 2 = 15 способов.
- 3. Шаг 3. Заполнение остальных четырёх мест. На каждое годится любая буква, кроме Л (иначе букв Л станет больше двух), то есть четыре варианта: А, Д, К, О. По правилу произведения это 4⁴ = 256.
- 4. Шаг 4. Два выбора независимы, значит перемножаем: 15 · 256 = 3840.
- 5.
Шаг 5. Проверка перебором. Программа на четыре строки считает то же самое и заодно страхует от ошибки в рассуждении:
from itertools import product
alph = 'АДКЛО' count = 0 for w in product(alph, repeat=6): if w.count('Л') == 2: count += 1 print(count) - 6. Шаг 6. Перебор проходит 5⁶ = 15 625 слов — мгновенно. Обратите внимание:
wздесь кортеж букв, иw.count('Л')считает буквы прямо в нём, склеивать его в строку не обязательно. - 7. Типичная ошибка этой задачи — взять 4⁴ · 6 вместо 4⁴ · C(6,2), то есть посчитать, что букву Л ставят «в одно из шести мест» дважды. Так получаются упорядоченные пары позиций, и каждое слово учитывается дважды: ответ выходит вдвое больше. Перебор такую ошибку ловит сразу.
Ответ: 3840
Почему на экзамене перебирают, а не считают формулой
Комбинаторная формула короче, но у неё два недостатка, и оба проявляются именно на экзамене.
Её легко построить неверно, и ошибку не видно. Забыли, что порядок не важен; не учли, что позиции связаны; перепутали «не более одной» с «ровно одной». Число получается правдоподобное, проверить его нечем.
Условия быстро становятся неформульными. «Цифра 0 не стоит рядом с цифрой 3» — попробуйте свести это к произведению и сочетаниям. Можно, но это отдельная задача минут на двадцать.
Перебор лишён обоих недостатков. Условие переписывается с русского на Python почти дословно, а число вариантов настолько мало, что о времени думать не приходится. Каркас один на все задания:
from itertools import product
alph = 'АДКЛО'
count = 0
for w in product(alph, repeat=6):
word = ''.join(w)
if <условие из задания>:
count += 1
print(count)
product(alph, repeat=6) выдаёт все кортежи длины 6 из букв алфавита, в том числе с повторами, и выдаёт их в лексикографическом порядке, если алфавит отсортирован. Второе свойство понадобится во второй половине урока, когда речь пойдёт о номерах слов.
| ровно k букв Х | word.count('Х') == k |
|---|---|
| не более одной буквы Х | word.count('Х') <= 1 |
| не содержит буквы Х | 'Х' not in word |
| начинается с буквы Х | word[0] == 'Х' |
| не начинается с нуля | word[0] != '0' — так задают «пятизначное число» |
| нет двух одинаковых подряд | all(word[i] != word[i+1] for i in range(len(word)-1)) |
| буквы Х и У не стоят рядом | all({word[i], word[i+1]} != {'Х','У'} for i in range(len(word)-1)) |
| все буквы различны | len(set(word)) == len(word) |
Разбор примера
Условие про соседство: ноль не рядом с тройкой
Определите количество пятизначных чисел, записанных в четверичной системе счисления, в записи которых ровно одна цифра 3, и при этом цифра 0 не стоит рядом с цифрой 3.
Показать решение по шагам
- 1.
from itertools import product
count = 0 for w in product('0123', repeat=5): if w[0] == '0': continue # не пятизначное if w.count('3') != 1: continue # ровно одна тройка if all({w[i], w[i + 1]} != {'0', '3'} for i in range(4)): count += 1 print(count) - 2. Шаг 1. Алфавит четверичной системы — цифры 0, 1, 2, 3. Всего кортежей длины 5 получается 4⁵ = 1024, и перебрать их можно хоть тысячу раз подряд.
- 3. Шаг 2. Первый
continueотсеивает числа, начинающиеся с нуля: слово «01230» не является пятизначным числом. Остаётся 3 · 4⁴ = 768 кандидатов. - 4. Шаг 3. Второй
continueоставляет те, где тройка ровно одна. Не «хотя бы одна» и не «не более одной» — условие читается буквально. - 5. Шаг 4. Проверка соседства. Пара соседних цифр
{w[i], w[i+1]}превращена в множество, и сравнение с{'0','3'}истинно, если рядом стоят ноль и тройка в любом порядке. Это короче, чем расписывать два случая: «0 слева, 3 справа» и наоборот.all(...)требует, чтобы условие выполнялось для всех четырёх соседних пар. - 6. Шаг 5. Проверим на примере. Число 13203: тройка встречается дважды — отсеивается вторым
continue. Число 10320: тройка одна, но пара (3, 2) в порядке, а вот (0, 3) на местах 2–3 запрещена → отсеивается. Число 13120: тройка одна; пары (1,3), (3,1), (1,2), (2,0) — ни одна не равна {0,3} → подходит. - 7. Шаг 6. Программа печатает 174. Заметьте, насколько дешевле это, чем разбирать случаи руками: «тройка на первом месте», «тройка на втором месте, слева не ноль», и так далее — пять случаев с подслучаями.
Ответ: 174
Вопрос на проверку
Сколько всего слов длины 5 можно составить из алфавита в 4 буквы, если буквы могут повторяться?
Ответить и проверить себя — после бесплатной регистрации.
Номер слова и слово по номеру
Слово — это число в системе счисления
Вторая половина линии 8 звучит так: «все слова записаны в алфавитном порядке и пронумерованы начиная с 1; под каким номером идёт слово такое-то» — или наоборот, «какое слово стоит под номером N».
За этим стоит точное соответствие.
Отсортируем алфавит по-русски и занумеруем буквы с нуля. Для букв М, А, С, Л, О алфавитный порядок такой: А, Л, М, О, С, и номера: А — 0, Л — 1, М — 2, О — 3, С — 4.
Теперь каждое слово превращается в набор цифр, то есть в число в системе счисления с основанием 5 (размер алфавита). Старшая буква слова — старший разряд числа.
Главное свойство: алфавитный порядок слов в точности совпадает с числовым порядком этих чисел. Оба сравнения идут слева направо и на первом различии дают ответ. Поэтому слово с номером 1 (самое первое) — это ААААА, то есть число 00000, а номер слова равен значению числа плюс один.
Отсюда обе формулы.
Номер по слову. Перевести буквы в цифры, вычислить значение как m-ичного числа, прибавить 1.
Слово по номеру. Вычесть 1, перевести полученное число в m-ичную систему, дополнить нулями слева до нужной длины и заменить цифры буквами. Дополнение нулями обязательно: число 7 в пятеричной системе записывается как «12», но слово длины пять — это «00012», то есть АААЛМ. Без ведущих нулей длина не сойдётся.
Разбор примера
Номер по слову: перебор и прямой счёт
Все пятибуквенные слова из букв М, А, С, Л, О записаны в алфавитном порядке и пронумерованы начиная с 1. Под каким номером идёт первое слово, которое содержит не более одной буквы А, ровно две буквы М и не содержит ни одной буквы Л?
Показать решение по шагам
- 1.
from itertools import product
alph = sorted('МАСЛО') # ['А', 'Л', 'М', 'О', 'С'] nomer = 0 for w in product(alph, repeat=5): nomer += 1 word = ''.join(w) if word.count('А') <= 1 and word.count('М') == 2 and 'Л' not in word: print(nomer, word) break - 2. Шаг 1.
sorted('МАСЛО')даёт список букв в алфавитном порядке: А, Л, М, О, С. Это ключевой момент: сортировать обязательно, иначеproductпойдёт в порядке исходной строки, и нумерация будет чужой. - 3. Шаг 2.
productпо отсортированному алфавиту выдаёт слова ровно в алфавитном порядке: ААААА, ААААЛ, ААААМ, ААААО, ААААС, АААЛА, … Поэтому достаточно вести счётчик и остановиться на первом подходящем. - 4. Шаг 3. Счётчик увеличивается до проверки условия, потому что нумерация начинается с 1: первое же слово ААААА должно получить номер 1, а не 0.
- 5. Шаг 4. Программа печатает 319 АММОО. Проверим условия глазами: букв А одна (не более одной ✔), букв М две ✔, буквы Л нет ✔
- 6. Шаг 5. Проверка счётом, без перебора. Переводим АММОО в цифры по нашей нумерации: А = 0, М = 2, М = 2, О = 3, О = 3. Получилось пятеричное число 02233.
- 7. Шаг 6. Считаем его значение: 0 · 5⁴ + 2 · 5³ + 2 · 5² + 3 · 5 + 3 = 0 + 2 · 125 + 2 · 25 + 15 + 3 = 250 + 50 + 15 + 3 = 318.
- 8. Шаг 7. Номер равен значению плюс один: 318 + 1 = 319. Совпало с перебором.
- 9. Шаг 8. Зачем нужны оба способа. Перебор надёжнее и пишется быстрее, но работает, только пока слов немного. Если бы в задании стояла длина 12 при алфавите из шести букв, слов было бы два миллиарда, и перебор не прошёл бы — тогда остаётся только счёт.
Ответ: 319
Разбор примера
Обратная задача: слово по номеру
Все слова длины 5 из букв К, О, Т записаны в алфавитном порядке и пронумерованы с 1. Какое слово стоит под номером 100?
Показать решение по шагам
- 1. Шаг 1. Алфавит по порядку: К, О, Т, то есть К = 0, О = 1, Т = 2. Основание системы равно 3, длина слова 5. Всего слов 3⁵ = 243, значит сотое существует.
- 2. Шаг 2. Вычитаем единицу: номер 100 соответствует значению 99. Единицу вычитают потому, что нумерация слов начинается с 1, а значения чисел — с 0.
- 3. Шаг 3. Переводим 99 в троичную систему делением с остатком. 99 : 3 = 33, остаток 0. 33 : 3 = 11, остаток 0. 11 : 3 = 3, остаток 2. 3 : 3 = 1, остаток 0. 1 : 3 = 0, остаток 1.
- 4. Шаг 4. Остатки выписываем снизу вверх, то есть в обратном порядке получения: 1, 0, 2, 0, 0. Получилось число 10200₃. Проверим: 1 · 81 + 0 · 27 + 2 · 9 + 0 · 3 + 0 = 81 + 18 = 99 ✔
- 5. Шаг 5. Разрядов вышло ровно пять — дополнять нулями слева не понадобилось. Если бы номер был маленьким, скажем 4 (значение 3, то есть 10₃), пришлось бы дописать нули до длины 5: 00010.
- 6. Шаг 6. Заменяем цифры буквами: 1 → О, 0 → К, 2 → Т, 0 → К, 0 → К. Слово: ОКТКК.
- 7.
Шаг 7. Проверка перебором:
from itertools import product
alph = sorted('КОТ') nomer = 0 for w in product(alph, repeat=5): nomer += 1 if nomer == 100: print(''.join(w)) breakПрограмма печатает ОКТКК — совпало.
Ответ: ОКТКК
Вопрос на проверку
Слова длины 4 из букв Б, А, В записаны в алфавитном порядке и пронумерованы с 1. Какое слово идёт первым?
Ответить и проверить себя — после бесплатной регистрации.
Ловушки линии 8
Алфавит не отсортирован. В условии буквы перечисляют в произвольном порядке — «М А С Л О», «К О Т», «А Г З О Р». Нумерация же идёт по алфавитному порядку. Строка sorted(...) стоит копейки, а её отсутствие меняет ответ полностью.
Нумерация с единицы, значения с нуля. Номер слова равен значению числа плюс один. В обратной задаче — сначала вычесть единицу, потом переводить. Ошибка на единицу здесь самая частая, и в переборе она возникает, если счётчик увеличивают после проверки условия.
Основание и показатель наоборот. Слов длины L из m букв — это mL, а не Lm. Проверяйте себя на маленьком случае: из двух букв слов длины 3 будет 2³ = 8 (ААА, ААБ, АБА, АББ, БАА, БАБ, ББА, БББ) — выпишите и убедитесь.
Три похожих слова, три разных условия. «Ровно», «не более» и «хотя бы» переносятся в код разными знаками: == k, <= k, >= 1. Читайте условие буквально и переносите в код дословно.
Ведущие нули в обратной задаче. Слово имеет фиксированную длину, а число — нет. Дополняйте запись нулями слева до нужной длины, иначе слово выйдет короче.
«Пятизначное число» — это запрет на ноль в начале. В задачах про числа, а не про слова, первый разряд не может быть нулевым, и это уменьшает перебор в m/(m−1) раз.
Что унести из урока
Слов длины L из алфавита размера m ровно mL — это правило произведения, применённое к L независимым позициям. Буквы в линии 8 всегда могут повторяться, поэтому ни факториалы, ни перестановки здесь не нужны.
Если на позиции наложено ограничение, число вариантов на ней просто уменьшается: «первая цифра не ноль» даёт 3 · 4⁴ вместо 4⁵. Если ограничение связывает разные позиции — «ровно две буквы Л», «нет двух одинаковых подряд», «ноль не рядом с тройкой», — формулу строить долго и рискованно, и на экзамене надёжнее перебрать всё через itertools.product: вариантов в линии 8 десятки тысяч, компьютер справится мгновенно.
Вторая половина линии 8 держится на одном соответствии: слово из отсортированного алфавита — это число в системе счисления с основанием m, а алфавитный порядок слов совпадает с числовым порядком. Отсюда номер слова равен значению числа плюс один, а слово по номеру получается переводом числа «номер минус один» в m-ичную систему с дополнением нулями слева.
И главная привычка: сортируйте алфавит. Условие перечисляет буквы как попало, нумерация же всегда алфавитная.
Задание №8 в формате экзамена
Ответить и проверить себя — после бесплатной регистрации.
Задание №8 в формате экзамена
Ответить и проверить себя — после бесплатной регистрации.
Вопрос с развёрнутым ответом
Почему для нахождения номера слова в алфавитном списке слово можно рассматривать как число в позиционной системе счисления?
Ответить и проверить себя — после бесплатной регистрации.
Задание №8 в формате экзамена
Ответить и проверить себя — после бесплатной регистрации.
Задание №8 в формате экзамена
Ответить и проверить себя — после бесплатной регистрации.