JustCaptain kod-buduschego

add theme 1.5, 1.6

anc · 4 дня назад 7efceb421dbc5c7b77700ed9dbec228ce6d15358
8 файлов
  • Показать разницуСкрыть разницу
    1 +# ⭐ Необязательные задачи
    2 +
    3 +> Дополнительная тренировка по теме. Решайте, если обязательные задачи уже сданы.
    4 +
    5 +---
    6 +
    7 +## Задача 1. Совершенное число
    8 +
    9 +### Условие
    10 +
    11 +Число называется **совершенным**, если оно равно сумме всех своих делителей, кроме самого себя. Например, `6 = 1 + 2 + 3`.
    12 +
    13 +Напишите функцию `int sumDivisors(int n)`, которая возвращает сумму собственных делителей числа, и с её помощью определите, является ли число совершенным.
    14 +
    15 +### Входные данные
    16 +
    17 +Одно натуральное число `n` (`n ≤ 10⁶`).
    18 +
    19 +### Выходные данные
    20 +
    21 +`YES`, если число совершенное, иначе `NO`.
    22 +
    23 +### Примеры
    24 +
    25 +| Ввод | Вывод |
    26 +|---|---|
    27 +| `6` | `YES` |
    28 +| `28` | `YES` |
    29 +| `12` | `NO` |
    30 +
    31 +> [!NOTE]
    32 +> Делители 28: 1, 2, 4, 7, 14 — их сумма 28. Делители 12: 1, 2, 3, 4, 6 — их сумма 16. У числа 1 собственных делителей нет, сумма равна 0, поэтому 1 не совершенное.
    33 +
    34 +---
    35 +
    36 +## Задача 2. Цифровой корень
    37 +
    38 +### Условие
    39 +
    40 +**Цифровой корень** числа получается так: складываем цифры числа, потом цифры результата, и так далее, пока не останется одна цифра.
    41 +
    42 +Напишите рекурсивную функцию `int digitSum(int n)` для суммы цифр и рекурсивную функцию `int digitalRoot(int n)` для цифрового корня.
    43 +
    44 +### Входные данные
    45 +
    46 +Одно натуральное число `n`.
    47 +
    48 +### Выходные данные
    49 +
    50 +Одно число — цифровой корень.
    51 +
    52 +### Примеры
    53 +
    54 +| Ввод | Вывод |
    55 +|---|---|
    56 +| `942` | `6` |
    57 +| `7` | `7` |
    58 +| `99999` | `9` |
    59 +
    60 +> [!TIP]
    61 +> `942 → 9 + 4 + 2 = 15 → 1 + 5 = 6`. База — `n < 10`, рекурсивный шаг — `digitalRoot(digitSum(n))`. Одна функция вызывает другую — это и есть композиция функций.
    62 +
    63 +---
    64 +
    65 +## Задача 3. Последовательность Коллатца
    66 +
    67 +### Условие
    68 +
    69 +Возьмём натуральное число `n`. Если оно чётное, делим его на 2, если нечётное — заменяем на `3n + 1`. Повторяем, пока не получим 1.
    70 +
    71 +Напишите **рекурсивную** функцию `int steps(int n)`, которая возвращает количество шагов до получения единицы.
    72 +
    73 +### Входные данные
    74 +
    75 +Одно натуральное число `n` (`n ≤ 10⁶`).
    76 +
    77 +### Выходные данные
    78 +
    79 +Одно число — количество шагов.
    80 +
    81 +### Примеры
    82 +
    83 +| Ввод | Вывод |
    84 +|---|---|
    85 +| `6` | `8` |
    86 +| `1` | `0` |
    87 +| `27` | `111` |
    88 +
    89 +> [!NOTE]
    90 +> Для 6: `6 → 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1` — восемь шагов. База — `n == 1` (шагов не нужно), рекурсивный шаг — `1 + steps(n / 2)` для чётного и `1 + steps(3 * n + 1)` для нечётного. Промежуточные значения могут быть больше `n`, поэтому для больших чисел безопаснее `long long`.
    91 +
    92 +---
    93 +
    94 +## Задача 4. Минимальный делитель
    95 +
    96 +### Условие
    97 +
    98 +Напишите функцию `int minDivisor(int n)`, которая возвращает наименьший делитель числа `n`, больший 1.
    99 +
    100 +### Входные данные
    101 +
    102 +Одно натуральное число `n` (`2 ≤ n ≤ 2·10⁹`).
    103 +
    104 +### Выходные данные
    105 +
    106 +Одно число — минимальный делитель.
    107 +
    108 +### Примеры
    109 +
    110 +| Ввод | Вывод |
    111 +|---|---|
    112 +| `15` | `3` |
    113 +| `16` | `2` |
    114 +| `17` | `17` |
    115 +
    116 +> [!TIP]
    117 +> Проверяйте делители, пока `i * i <= n`. Если делитель не нашёлся, число простое и ответ — само `n`. Для `n` около 2·10⁹ произведение `i * i` может не поместиться в `int` — объявите `i` как `long long`.
    118 +
    119 +---
    120 +
    121 +## Задача 5. Синус через ряд Тейлора
    122 +
    123 +### Условие
    124 +
    125 +Вычислите `sin(x)` с помощью ряда Тейлора:
    126 +
    127 +```text
    128 +sin(x) = x - x³/3! + x⁵/5! - x⁷/7! + ...
    129 +```
    130 +
    131 +Суммируйте члены ряда, пока модуль очередного члена больше `10⁻⁶`. Оформите вычисление в виде функции `double taylorSine(double x)`. Пользоваться функцией `sin` из `<cmath>` нельзя.
    132 +
    133 +### Входные данные
    134 +
    135 +Одно вещественное число `x` (`|x| ≤ 10`) — угол в радианах.
    136 +
    137 +### Выходные данные
    138 +
    139 +Значение `sin(x)` с шестью знаками после запятой.
    140 +
    141 +### Примеры
    142 +
    143 +| Ввод | Вывод |
    144 +|---|---|
    145 +| `0` | `0.000000` |
    146 +| `1.5707963` | `1.000000` |
    147 +| `1` | `0.841471` |
    148 +
    149 +> [!TIP]
    150 +> Не считайте факториал и степень заново для каждого члена. Следующий член получается из предыдущего: `term = -term * x * x / ((2 * n) * (2 * n + 1))`, где `n` — номер шага. Для вывода используйте `fixed << setprecision(6)`.
  • Показать разницуСкрыть разницу
    1 +# ✅ Обязательные задачи (LMS)
    2 +
    3 +> Эти задачи нужно решить и сдать в LMS.
    4 +
    5 +---
    6 +
    7 +## Задача 1. Ханойские башни
    8 +
    9 +### Условие
    10 +
    11 +Головоломка «Ханойские башни» состоит из трёх стержней и `N` дисков разного размера. В начале все диски надеты на первый стержень в порядке убывания: самый большой внизу, самый маленький наверху. Нужно перенести всю пирамиду на третий стержень, соблюдая два правила:
    12 +
    13 +- за один ход перекладывается ровно один диск;
    14 +- больший диск нельзя класть поверх меньшего.
    15 +
    16 +Второй стержень можно использовать как вспомогательный. Определите, за какое наименьшее количество ходов это можно сделать.
    17 +
    18 +Задачу нужно решить **рекурсивно**: реализуйте функцию `int hanoi(int n)`, которая возвращает минимальное число ходов.
    19 +
    20 +### Входные данные
    21 +
    22 +Одно натуральное число `N` — количество дисков (`1 ≤ N ≤ 30`).
    23 +
    24 +### Выходные данные
    25 +
    26 +Одно число — минимальное количество ходов.
    27 +
    28 +### Пример
    29 +
    30 +**Ввод:**
    31 +
    32 +```text
    33 +3
    34 +```
    35 +
    36 +**Вывод:**
    37 +
    38 +```text
    39 +7
    40 +```
    41 +
    42 +> [!TIP]
    43 +> Чтобы перенести `N` дисков, нужно перенести `N − 1` дисков на вспомогательный стержень, переложить самый большой диск и снова перенести `N − 1` дисков поверх него. Отсюда `hanoi(n) = 2 * hanoi(n - 1) + 1`, а база — `hanoi(1) = 1`.
    44 +
    45 +---
    46 +
    47 +## Задача 2. Количество разменов
    48 +
    49 +### Условие
    50 +
    51 +Даны три номинала монет `a`, `b`, `c` и сумма `S`. Определите, сколькими способами можно набрать сумму `S` этими монетами. Каждую монету можно использовать любое количество раз, порядок монет не важен.
    52 +
    53 +Напишите функцию `int count_ways(int a, int b, int c, int S)`, которая возвращает количество способов.
    54 +
    55 +### Входные данные
    56 +
    57 +Четыре натуральных числа `a`, `b`, `c` и `S`, записанных через пробел.
    58 +
    59 +### Выходные данные
    60 +
    61 +Одно число — количество способов размена.
    62 +
    63 +### Пример
    64 +
    65 +**Ввод:**
    66 +
    67 +```text
    68 +1 2 5 5
    69 +```
    70 +
    71 +**Вывод:**
    72 +
    73 +```text
    74 +4
    75 +```
    76 +
    77 +> [!NOTE]
    78 +> Способы набрать 5: `5`, `1 + 2 + 2`, `1 + 1 + 1 + 2`, `1 + 1 + 1 + 1 + 1`. Перебирайте вложенными циклами количество монет номинала `a` и `b`, а остаток проверяйте на делимость на `c`: `(S - i*a - j*b) % c == 0`.
    79 +
    80 +---
    81 +
    82 +## Задача 3. Наибольший общий делитель
    83 +
    84 +### Условие
    85 +
    86 +Напишите **рекурсивную** функцию `int gcd(int a, int b)`, которая вычисляет НОД двух чисел по алгоритму Евклида. С её помощью найдите НОД трёх чисел.
    87 +
    88 +### Входные данные
    89 +
    90 +Три натуральных числа.
    91 +
    92 +### Выходные данные
    93 +
    94 +Одно число — их наибольший общий делитель.
    95 +
    96 +### Пример
    97 +
    98 +**Ввод:**
    99 +
    100 +```text
    101 +36 48 60
    102 +```
    103 +
    104 +**Вывод:**
    105 +
    106 +```text
    107 +12
    108 +```
    109 +
    110 +> [!TIP]
    111 +> Алгоритм Евклида: `gcd(a, b) = gcd(b, a % b)`, база — `gcd(a, 0) = a`. Для трёх чисел используйте вложенный вызов: `gcd(gcd(a, b), c)`.
    112 +
    113 +---
    114 +
    115 +## Задача 4. Синхронизация времени (SNTP)
    116 +
    117 +### Условие
    118 +
    119 +Клиент отправляет запрос на сервер и запоминает время отправления `A`. Сервер получает запрос в момент `B` (по часам сервера) и сразу отправляет клиенту ответ, в котором указано время `B`. Клиент получает ответ в момент `C` (по своим часам). Задержки в сети туда и обратно одинаковы.
    120 +
    121 +Определите точное время, которое нужно установить на часах клиента в момент получения ответа.
    122 +
    123 +### Входные данные
    124 +
    125 +Три строки — временные метки `A`, `B` и `C` в формате `hh:mm:ss`.
    126 +
    127 +### Выходные данные
    128 +
    129 +Точное время в формате `hh:mm:ss`.
    130 +
    131 +### Пример
    132 +
    133 +**Ввод:**
    134 +
    135 +```text
    136 +15:01:00
    137 +18:09:45
    138 +15:01:40
    139 +```
    140 +
    141 +**Вывод:**
    142 +
    143 +```text
    144 +18:10:05
    145 +```
    146 +
    147 +> [!NOTE]
    148 +> Запрос шёл туда и обратно `C − A = 40` секунд, значит, в одну сторону — 20 секунд. Точное время: `B + (C − A) / 2 = 18:09:45 + 20 = 18:10:05`.
    149 +
    150 +> [!TIP]
    151 +> - Считывайте время с разделителями: `cin >> h >> sep >> m >> sep >> s;`, где `char sep`.
    152 +> - Вынесите перевод в секунды в функцию `int toSeconds(int h, int m, int s)`.
    153 +> - Время может перейти через полночь, поэтому используйте `(x + 86400) % 86400`.
    154 +> - Для ведущих нулей: `setfill('0') << setw(2)` из `<iomanip>`.
    155 +
    156 +---
    157 +
    158 +## Задача 5. Бизнес-центр
    159 +
    160 +### Условие
    161 +
    162 +Бизнес-центр — `N`-этажное здание. На каждом этаже работает ровно один сотрудник. Утром все сотрудники приезжают на парковку в подвале (на один этаж ниже первого).
    163 +
    164 +Лифт один раз отвозит всех желающих на выбранный этаж `X`, тратя `C` секунд на каждый этаж пути. Дальше каждый сотрудник добирается до своего этажа пешком: подъём на один этаж занимает `A` секунд, спуск — `B` секунд. Сотрудник может и не пользоваться лифтом, а сразу пойти пешком вверх с парковки.
    165 +
    166 +Найдите минимальное суммарное время: время работы лифта плюс время, которое все сотрудники тратят на дорогу.
    167 +
    168 +### Входные данные
    169 +
    170 +Четыре натуральных числа `N`, `A`, `B`, `C`.
    171 +
    172 +### Выходные данные
    173 +
    174 +Одно число — минимальное время.
    175 +
    176 +### Пример
    177 +
    178 +**Ввод:**
    179 +
    180 +```text
    181 +3 2 1 1
    182 +```
    183 +
    184 +**Вывод:**
    185 +
    186 +```text
    187 +5
    188 +```
    189 +
    190 +> [!NOTE]
    191 +> Если лифт едет на 2-й этаж: лифт тратит `2 · 1 = 2` секунды, сотрудник 1-го этажа спускается за 1 секунду, сотрудник 2-го уже на месте, сотрудник 3-го поднимается за 2 секунды. Итого `2 + 1 + 0 + 2 = 5`.
    192 +
    193 +> [!TIP]
    194 +> Переберите этаж `X` от 1 до `N`. Для каждого сотрудника `i` выберите лучшее из двух: пешком с парковки (`i * A`) или от этажа `X` на лифте. Используйте `long long`.
    195 +
    196 +---
    197 +
    198 +## Задача 6. Числа Фибоначчи без циклов
    199 +
    200 +### Условие
    201 +
    202 +Последовательность Фибоначчи задаётся так: `a₀ = 0`, `a₁ = 1`, `aₖ = aₖ₋₁ + aₖ₋₂` при `k > 1`.
    203 +
    204 +Найдите `N`-е число Фибоначчи. **В программе запрещается использовать циклы.**
    205 +
    206 +### Входные данные
    207 +
    208 +Одно целое неотрицательное число `N` (`N ≤ 30`).
    209 +
    210 +### Выходные данные
    211 +
    212 +Одно число — `N`-е число Фибоначчи.
    213 +
    214 +### Пример
    215 +
    216 +**Ввод:**
    217 +
    218 +```text
    219 +7
    220 +```
    221 +
    222 +**Вывод:**
    223 +
    224 +```text
    225 +13
    226 +```
    227 +
    228 +> [!NOTE]
    229 +> Первые числа последовательности: 0, 1, 1, 2, 3, 5, 8, 13, ... Под номером 7 (считая с нуля) стоит 13. У рекурсивной функции две базы: `n == 0` и `n == 1`.
  • Показать разницуСкрыть разницу
    1 +# 🧑‍🏫 Практика
    2 +
    3 +> Задачи, которые решаем на занятиях.
    4 +
    5 +---
    6 +
    7 +## Задача 1. Сумма цифр числа
    8 +
    9 +### Условие
    10 +
    11 +Дано натуральное число `n`. Найдите сумму его цифр, используя **рекурсивную** функцию `int sumDigits(int n)`.
    12 +
    13 +### Входные данные
    14 +
    15 +Одно натуральное число `n`.
    16 +
    17 +### Выходные данные
    18 +
    19 +Одно число — сумма цифр.
    20 +
    21 +### Примеры
    22 +
    23 +**Ввод:**
    24 +
    25 +```text
    26 +1234
    27 +```
    28 +
    29 +**Вывод:**
    30 +
    31 +```text
    32 +10
    33 +```
    34 +
    35 +**Ввод:**
    36 +
    37 +```text
    38 +507
    39 +```
    40 +
    41 +**Вывод:**
    42 +
    43 +```text
    44 +12
    45 +```
    46 +
    47 +> [!NOTE]
    48 +> База рекурсии — однозначное число (`n < 10`): сумма его цифр равна ему самому. Рекурсивный шаг — последняя цифра `n % 10` плюс сумма цифр числа без неё `sumDigits(n / 10)`.
    49 +>
    50 +> ```text
    51 +> sumDigits(1234) = 4 + sumDigits(123)
    52 +> = 4 + 3 + sumDigits(12)
    53 +> = 4 + 3 + 2 + sumDigits(1)
    54 +> = 4 + 3 + 2 + 1 = 10
    55 +> ```
    56 +
    57 +---
    58 +
    59 +## Задача 2. Простые близнецы
    60 +
    61 +### Условие
    62 +
    63 +Даны два натуральных числа. Напишите функцию `bool isPrime(int n)`, которая определяет, является ли число простым. С её помощью определите, являются ли данные числа **простыми близнецами** — простыми числами, которые отличаются на 2.
    64 +
    65 +### Входные данные
    66 +
    67 +Два натуральных числа через пробел.
    68 +
    69 +### Выходные данные
    70 +
    71 +`YES`, если числа — простые близнецы, иначе `NO`.
    72 +
    73 +### Примеры
    74 +
    75 +**Ввод:**
    76 +
    77 +```text
    78 +17 19
    79 +```
    80 +
    81 +**Вывод:**
    82 +
    83 +```text
    84 +YES
    85 +```
    86 +
    87 +**Ввод:**
    88 +
    89 +```text
    90 +17 20
    91 +```
    92 +
    93 +**Вывод:**
    94 +
    95 +```text
    96 +NO
    97 +```
    98 +
    99 +> [!NOTE]
    100 +> Числа 17 и 19 простые, и `19 − 17 = 2`. Число 20 составное, поэтому во втором примере ответ `NO`. Не забудьте, что 0 и 1 простыми не являются, а делители достаточно проверять, пока `i * i <= n`.
    101 +
    102 +---
    103 +
    104 +## Задача 3. Симметричное число
    105 +
    106 +### Условие
    107 +
    108 +Напишите **рекурсивную** функцию `int reverseNumber(int n)`, которая возвращает число, записанное теми же цифрами в обратном порядке. С её помощью определите, является ли число палиндромом.
    109 +
    110 +### Входные данные
    111 +
    112 +Одно натуральное число.
    113 +
    114 +### Выходные данные
    115 +
    116 +`YES`, если число — палиндром, иначе `NO`.
    117 +
    118 +### Примеры
    119 +
    120 +**Ввод:**
    121 +
    122 +```text
    123 +12321
    124 +```
    125 +
    126 +**Вывод:**
    127 +
    128 +```text
    129 +YES
    130 +```
    131 +
    132 +**Ввод:**
    133 +
    134 +```text
    135 +1231
    136 +```
    137 +
    138 +**Вывод:**
    139 +
    140 +```text
    141 +NO
    142 +```
    143 +
    144 +> [!TIP]
    145 +> Удобно добавить второй параметр со значением по умолчанию: `int reverseNumber(int n, int reversed = 0)`. На каждом шаге последняя цифра переносится в `reversed`: `reverseNumber(n / 10, reversed * 10 + n % 10)`. База — `n == 0`, тогда ответ уже собран в `reversed`.
    146 +
    147 +---
    148 +
    149 +## Задача 4. Наименьшее общее кратное
    150 +
    151 +### Условие
    152 +
    153 +Напишите рекурсивную функцию `int gcd(int a, int b)` для НОД по алгоритму Евклида и функцию `long long lcm(long long a, long long b)`, которая с её помощью вычисляет НОК двух чисел. Найдите НОК трёх чисел.
    154 +
    155 +### Входные данные
    156 +
    157 +Три натуральных числа, каждое не больше 1000.
    158 +
    159 +### Выходные данные
    160 +
    161 +Одно число — наименьшее общее кратное.
    162 +
    163 +### Пример
    164 +
    165 +**Ввод:**
    166 +
    167 +```text
    168 +4 6 10
    169 +```
    170 +
    171 +**Вывод:**
    172 +
    173 +```text
    174 +60
    175 +```
    176 +
    177 +> [!NOTE]
    178 +> НОК выражается через НОД: `lcm(a, b) = a * b / gcd(a, b)`. Для трёх чисел — `lcm(lcm(a, b), c)`. Здесь `lcm(4, 6) = 12`, а `lcm(12, 10) = 120 / 2 = 60`. Произведение `a * b` быстро растёт, поэтому НОК считаем в `long long`.
    179 +
    180 +---
    181 +
    182 +## Задача 5. Башни кубиков
    183 +
    184 +### Условие
    185 +
    186 +Даны высоты трёх башен. Напишите функции `int max3(int a, int b, int c)` и `int min3(int a, int b, int c)` и с их помощью найдите разницу между самой высокой и самой низкой башней.
    187 +
    188 +### Входные данные
    189 +
    190 +Три целых числа через пробел.
    191 +
    192 +### Выходные данные
    193 +
    194 +Одно число — разница между максимумом и минимумом.
    195 +
    196 +### Пример
    197 +
    198 +**Ввод:**
    199 +
    200 +```text
    201 +18 25 13
    202 +```
    203 +
    204 +**Вывод:**
    205 +
    206 +```text
    207 +12
    208 +```
    209 +
    210 +> [!NOTE]
    211 +> Самая высокая башня — 25, самая низкая — 13, разница `25 − 13 = 12`. Внутри `max3` и `min3` начинайте с первого числа (`int m = a;`), а не с нуля — иначе функция ошибётся на отрицательных числах.
  • Показать разницуСкрыть разницу
    1 +# 📘 Тема 1.5. Необходимый материал
    2 +
    3 +> Шпаргалка по функциям, декомпозиции и рекурсии.
    4 +
    5 +---
    6 +
    7 +## 1. Что такое функция
    8 +
    9 +**Функция** — именованный блок кода, который выполняет одну задачу и может быть вызван из других частей программы.
    10 +
    11 +Зачем нужны функции:
    12 +
    13 +- **Повторное использование.** Код пишется один раз, а вызывается сколько угодно раз.
    14 +- **Модульность.** Программа разбивается на логические блоки, её проще читать и отлаживать.
    15 +- **Одно место для изменений.** Если формула поменялась, правим её в одной функции, а не в десяти местах.
    16 +
    17 +**Декомпозиция** — разбиение большой задачи на небольшие подзадачи, каждая из которых оформляется отдельной функцией.
    18 +
    19 +Термины:
    20 +
    21 +| Термин | Значение |
    22 +|---|---|
    23 +| **параметр** | переменная в заголовке функции, через которую она получает данные (`int x`) |
    24 +| **аргумент** | конкретное значение, которое передаётся при вызове (`square(5)` — аргумент `5`) |
    25 +| **возвращаемое значение** | результат, который функция отдаёт через `return` |
    26 +| **локальная переменная** | переменная, объявленная внутри функции; снаружи её не видно |
    27 +| **прототип** | объявление функции без тела |
    28 +
    29 +> [!NOTE]
    30 +> `main` — тоже функция. Она возвращает `int`, и `return 0;` в конце сообщает системе, что программа завершилась успешно.
    31 +
    32 +---
    33 +
    34 +## 2. Синтаксис функции
    35 +
    36 +```cpp
    37 +тип имя_функции(параметры) {
    38 + // инструкции
    39 + return значение;
    40 +}
    41 +```
    42 +
    43 +- **тип** — тип возвращаемого значения (`int`, `long long`, `double`, `bool`, `string`). Если функция ничего не возвращает — `void`.
    44 +- **имя** — пишется с маленькой буквы по правилам имён переменных.
    45 +- **параметры** — входные данные через запятую, у каждого свой тип.
    46 +- **`return`** — возвращает значение и **сразу завершает** функцию.
    47 +
    48 +```cpp
    49 +int square(int x) {
    50 + return x * x;
    51 +}
    52 +
    53 +int main() {
    54 + cout << square(3) << endl; // 9
    55 + cout << square(square(2)) << endl; // 16
    56 + int y = square(4) + 1; // 17
    57 + return 0;
    58 +}
    59 +```
    60 +
    61 +> [!TIP]
    62 +> Функция — это «чёрный ящик»: даём ей вход, получаем выход. Результат можно вывести, сохранить в переменную или подставить в другое выражение, в том числе в вызов другой функции.
    63 +
    64 +---
    65 +
    66 +## 3. Виды подпрограмм
    67 +
    68 +| Вид | Что делает | Пример |
    69 +|---|---|---|
    70 +| **процедура** (`void`) | выполняет действие, ничего не возвращает | `void printHello()` |
    71 +| **функция** | вычисляет и возвращает значение | `int square(int x)` |
    72 +| **рекурсивная функция** | вызывает сама себя | `int factorial(int n)` |
    73 +
    74 +```cpp
    75 +// процедура
    76 +void printHello() {
    77 + cout << "Hello!" << endl;
    78 +}
    79 +
    80 +// функция
    81 +int square(int x) {
    82 + return x * x;
    83 +}
    84 +
    85 +// рекурсия
    86 +int factorial(int n) {
    87 + if (n <= 1) return 1;
    88 + return n * factorial(n - 1);
    89 +}
    90 +```
    91 +
    92 +---
    93 +
    94 +## 4. Прототип функции
    95 +
    96 +Функцию нужно объявить **до** того места, где она вызывается. Если хочется написать её после `main`, сверху ставят **прототип** — объявление без тела.
    97 +
    98 +```cpp
    99 +#include <iostream>
    100 +using namespace std;
    101 +
    102 +int square(int x); // прототип
    103 +
    104 +int main() {
    105 + cout << square(5) << endl;
    106 + return 0;
    107 +}
    108 +
    109 +int square(int x) { // определение
    110 + return x * x;
    111 +}
    112 +```
    113 +
    114 +> [!WARNING]
    115 +> Без прототипа такой код не скомпилируется: компилятор читает файл сверху вниз и в `main` ещё не знает, что такое `square`.
    116 +
    117 +---
    118 +
    119 +## 5. Передача параметров по значению
    120 +
    121 +Функция получает **копию** аргумента. Изменения внутри функции на оригинал не влияют.
    122 +
    123 +```cpp
    124 +void square(int m) {
    125 + m = m * m;
    126 + cout << "In square: m = " << m << endl;
    127 +}
    128 +
    129 +int main() {
    130 + int n = 4;
    131 + cout << "Before: n = " << n << endl;
    132 + square(n);
    133 + cout << "After: n = " << n << endl;
    134 + return 0;
    135 +}
    136 +```
    137 +
    138 +```text
    139 +Before: n = 4
    140 +In square: m = 16
    141 +After: n = 4
    142 +```
    143 +
    144 +Здесь `m` — копия `n`. Изменение `m` не меняет `n`. Чтобы функция изменила оригинал, нужна передача по ссылке или указателю — к этому мы ещё вернёмся.
    145 +
    146 +### Значение параметра по умолчанию
    147 +
    148 +Параметру можно задать значение по умолчанию — тогда при вызове его можно не указывать.
    149 +
    150 +```cpp
    151 +int reverseNumber(int n, int reversed = 0) { ... }
    152 +
    153 +reverseNumber(123); // reversed = 0
    154 +reverseNumber(123, 5); // reversed = 5
    155 +```
    156 +
    157 +---
    158 +
    159 +## 6. Возврат указателя
    160 +
    161 +Если функция возвращает указатель, он должен указывать на память, которая **жива после выхода** из функции, либо быть равным `nullptr`.
    162 +
    163 +```cpp
    164 +// ❌ ошибка: a и b — локальные копии, после выхода из функции их нет
    165 +int* maxPtr(int a, int b) {
    166 + if (a > b) return &a;
    167 + return &b;
    168 +}
    169 +```
    170 +
    171 +```cpp
    172 +// ✅ указатели ссылаются на переменные из main
    173 +int* maxPtr(int* a, int* b) {
    174 + if (*a > *b) return a;
    175 + return b;
    176 +}
    177 +
    178 +int main() {
    179 + int n = 5, m = 4;
    180 + int* p = maxPtr(&n, &m);
    181 + cout << *p << endl; // 5
    182 + return 0;
    183 +}
    184 +```
    185 +
    186 +> [!CAUTION]
    187 +> Указатель на локальную переменную называют **висячим**: он показывает на память, которая уже освобождена. Программа может выдать мусор или упасть.
    188 +
    189 +---
    190 +
    191 +## 7. Декомпозиция: пример с рядом Тейлора
    192 +
    193 +Задача: вычислить `sin(x)` через ряд
    194 +
    195 +```text
    196 +sin(x) = x - x³/3! + x⁵/5! - x⁷/7! + ...
    197 +```
    198 +
    199 +Суммируем члены, пока очередной член не станет меньше точности `10⁻⁶`.
    200 +
    201 +Каждый следующий член получается из предыдущего: `term = -term * x * x / ((2n) * (2n + 1))`. Поэтому факториал в явном виде считать не нужно.
    202 +
    203 +```cpp
    204 +#include <iostream>
    205 +#include <cmath>
    206 +using namespace std;
    207 +
    208 +double taylorSine(double x, double epsilon = 1e-6) {
    209 + double result = 0.0;
    210 + double term = x;
    211 + int n = 1;
    212 + while (fabs(term) > epsilon) {
    213 + result += term;
    214 + term = -term * x * x / ((2 * n) * (2 * n + 1));
    215 + n++;
    216 + }
    217 + return result;
    218 +}
    219 +
    220 +int main() {
    221 + double x;
    222 + cin >> x;
    223 + cout << "Taylor: " << taylorSine(x) << endl;
    224 + cout << "Library: " << sin(x) << endl;
    225 + return 0;
    226 +}
    227 +```
    228 +
    229 +> [!TIP]
    230 +> Признаки хорошей декомпозиции: `main` короткий и читается как план решения, каждая функция делает одну вещь, каждую функцию можно проверить отдельно.
    231 +
    232 +---
    233 +
    234 +## 8. Рекурсия
    235 +
    236 +**Рекурсия** — приём, при котором функция вызывает саму себя для задачи меньшего размера.
    237 +
    238 +У рекурсивной функции всегда две части:
    239 +
    240 +1. **База рекурсии** — условие, при котором функция возвращает ответ сразу, без вызова себя.
    241 +2. **Рекурсивный шаг** — вызов функции с аргументом, который приближает к базе.
    242 +
    243 +```cpp
    244 +int factorial(int n) {
    245 + if (n <= 1) {
    246 + return 1; // база
    247 + }
    248 + return n * factorial(n - 1); // рекурсивный шаг
    249 +}
    250 +```
    251 +
    252 +Как это работает для `n = 5`:
    253 +
    254 +```text
    255 +factorial(5)
    256 += 5 * factorial(4)
    257 += 5 * 4 * factorial(3)
    258 += 5 * 4 * 3 * factorial(2)
    259 += 5 * 4 * 3 * 2 * factorial(1)
    260 += 5 * 4 * 3 * 2 * 1
    261 += 120
    262 +```
    263 +
    264 +Каждый вызов ждёт результата следующего и хранится в **стеке вызовов**. Когда достигнута база, результаты начинают «возвращаться» вверх.
    265 +
    266 +> [!CAUTION]
    267 +> Без базы (или если база никогда не достигается) функция вызывает себя бесконечно. Стек вызовов заканчивается, и программа падает — это **переполнение стека**.
    268 +
    269 +---
    270 +
    271 +## 9. Последовательности и рекуррентные формулы
    272 +
    273 +**Последовательность** — упорядоченный набор чисел `a₁, a₂, a₃, ...`, где `n` — номер члена.
    274 +
    275 +| Последовательность | Формула n-го члена | Пример |
    276 +|---|---|---|
    277 +| арифметическая прогрессия | `aₙ = a₁ + (n − 1) · d` | `a₁ = 2, d = 3` → 2, 5, 8, 11, ... |
    278 +| геометрическая прогрессия | `aₙ = a₁ · r^(n − 1)` | `a₁ = 2, r = 3` → 2, 6, 18, 54, ... |
    279 +
    280 +**Рекуррентная формула** выражает член последовательности через предыдущие: `aₙ = f(aₙ₋₁, aₙ₋₂, ...)`.
    281 +
    282 +| Последовательность | Начальные условия | Рекуррентная формула |
    283 +|---|---|---|
    284 +| факториал | `0! = 1` | `n! = n · (n − 1)!` |
    285 +| Фибоначчи | `F(0) = 0`, `F(1) = 1` | `F(n) = F(n − 1) + F(n − 2)` |
    286 +| член ряда Тейлора для `sin` | `T₀ = x` | `Tₙ = −Tₙ₋₁ · x² / ((2n)(2n + 1))` |
    287 +| НОД (алгоритм Евклида) | `gcd(a, 0) = a` | `gcd(a, b) = gcd(b, a % b)` |
    288 +| Ханойские башни | `h(1) = 1` | `h(n) = 2 · h(n − 1) + 1` |
    289 +
    290 +### Как перевести последовательность в рекуррентную формулу
    291 +
    292 +1. Найдите закономерность: как следующий член связан с предыдущими.
    293 +2. Выразите `aₙ` через `aₙ₋₁`, `aₙ₋₂`, ...
    294 +3. Запишите начальные условия — они станут **базой** рекурсии.
    295 +4. Проверьте формулу на нескольких первых членах.
    296 +
    297 +Пример: 1, 1, 2, 6, 24, 120, ... — каждый член в `n` раз больше предыдущего, значит, `aₙ = n · aₙ₋₁`, `a₀ = 1`. Проверка: `a₃ = 3 · 2 = 6` ✅.
    298 +
    299 +> [!TIP]
    300 +> Рекуррентная формула переводится в код почти дословно: начальные условия → `if (...) return ...;`, формула → `return ...;` с вызовом той же функции.
    301 +
    302 +---
    303 +
    304 +## 10. Шаблоны рекурсивных функций
    305 +
    306 +### Числа Фибоначчи
    307 +
    308 +```cpp
    309 +int fibonacci(int n) {
    310 + if (n == 0) return 0; // база
    311 + if (n == 1) return 1; // база
    312 + return fibonacci(n - 1) + fibonacci(n - 2);
    313 +}
    314 +```
    315 +
    316 +> [!WARNING]
    317 +> Такая функция работает медленно: `fibonacci(5)` вызывает `fibonacci(3)` дважды, `fibonacci(2)` — трижды, и с ростом `n` число вызовов растёт экспоненциально. Для `n ≤ 30` это нормально, для `n = 50` — уже слишком долго. На олимпиадах в таких случаях считают циклом.
    318 +
    319 +### Сумма цифр числа
    320 +
    321 +```cpp
    322 +int sumDigits(int n) {
    323 + if (n < 10) return n; // одна цифра
    324 + return n % 10 + sumDigits(n / 10); // последняя цифра + сумма остальных
    325 +}
    326 +```
    327 +
    328 +### НОД (алгоритм Евклида)
    329 +
    330 +```cpp
    331 +int gcd(int a, int b) {
    332 + if (b == 0) return a;
    333 + return gcd(b, a % b);
    334 +}
    335 +
    336 +// НОД трёх чисел
    337 +cout << gcd(gcd(a, b), c) << endl;
    338 +```
    339 +
    340 +### Переворот числа
    341 +
    342 +```cpp
    343 +int reverseNumber(int n, int reversed = 0) {
    344 + if (n == 0) return reversed;
    345 + return reverseNumber(n / 10, reversed * 10 + n % 10);
    346 +}
    347 +```
    348 +
    349 +### Проверка на простоту (функция с `bool`)
    350 +
    351 +```cpp
    352 +bool isPrime(int n) {
    353 + if (n < 2) return false;
    354 + for (int i = 2; i * i <= n; i++) {
    355 + if (n % i == 0) return false;
    356 + }
    357 + return true;
    358 +}
    359 +```
    360 +
    361 +> [!NOTE]
    362 +> Условие `i * i <= n` равносильно `i <= sqrt(n)`, но работает только с целыми числами и не требует `<cmath>`.
    363 +
    364 +---
    365 +
    366 +## 11. Чтение данных с разделителями
    367 +
    368 +Если данные записаны как `15:01:40`, удобно считывать разделитель в переменную типа `char`:
    369 +
    370 +```cpp
    371 +int h, m, s;
    372 +char sep;
    373 +cin >> h >> sep >> m >> sep >> s; // sep получает ':'
    374 +```
    375 +
    376 +`cin` прочитает число, затем один символ, затем снова число.
    377 +
    378 +---
    379 +
    380 +## 12. Типичные ошибки
    381 +
    382 +| ❌ Неправильно | ✅ Правильно |
    383 +|---|---|
    384 +| Написали функцию, но не вызвали её в `main` | вызвать функцию и использовать результат |
    385 +| `int f(int x) { if (x > 0) return 1; }` — нет `return` для `x <= 0` | `return` в каждой ветке |
    386 +| `int average(int a, int b)` возвращает дробный результат | тип возвращаемого значения `double` |
    387 +| Вызов функции выше её определения без прототипа | прототип сверху или определение до `main` |
    388 +| Использование переменной из `main` внутри функции | передать её параметром |
    389 +| Рекурсия без базы или с базой, которая не достигается | `if (...) return ...;` в начале функции |
    390 +| `gcd(a % b, b)` | `gcd(b, a % b)` |
    391 +| `return &a;` — указатель на локальную переменную | возвращать указатель на внешние данные или `nullptr` |
    392 +| Одна огромная функция на всё решение | несколько небольших функций |
    393 +
    394 +---
    395 +
    396 +## 13. Шаблон программы
    397 +
    398 +```cpp
    399 +#include <iostream>
    400 +using namespace std;
    401 +
    402 +// вспомогательные функции
    403 +
    404 +int main() {
    405 + // ввод данных
    406 +
    407 + // вызов функций
    408 +
    409 + // вывод ответа
    410 +
    411 + return 0;
    412 +}
    413 +```
  • Показать разницуСкрыть разницу
    1 +# ⭐ Необязательные задачи
    2 +
    3 +> Дополнительная тренировка по теме. Решайте, если обязательные задачи уже сданы.
    4 +
    5 +---
    6 +
    7 +## Задача 1. Зеркальное слово
    8 +
    9 +### Условие
    10 +
    11 +Дано слово. Определите, является ли оно палиндромом, то есть одинаково ли читается слева направо и справа налево.
    12 +
    13 +### Входные данные
    14 +
    15 +Одно слово из строчных латинских букв.
    16 +
    17 +### Выходные данные
    18 +
    19 +`YES`, если слово — палиндром, иначе `NO`.
    20 +
    21 +### Примеры
    22 +
    23 +| Ввод | Вывод |
    24 +|---|---|
    25 +| `level` | `YES` |
    26 +| `hello` | `NO` |
    27 +| `a` | `YES` |
    28 +
    29 +> [!TIP]
    30 +> Заведите два индекса: `left = 0` и `right = s.size() - 1`. Пока `left < right`, сравнивайте `s[left]` и `s[right]` и сдвигайте индексы навстречу друг другу. Проверку удобно вынести в функцию `bool isPalindrome(string s)`.
    31 +
    32 +---
    33 +
    34 +## Задача 2. Самая популярная задача
    35 +
    36 +### Условие
    37 +
    38 +На олимпиаде было 10 задач с номерами от 1 до 10. Известно, какую задачу сдал каждый из `N` участников. Определите номер задачи, которую сдавали чаще всего. Если таких задач несколько, выведите задачу с наименьшим номером.
    39 +
    40 +### Входные данные
    41 +
    42 +В первой строке вводится число `N` (`1 ≤ N ≤ 1000`). Во второй строке — `N` чисел от 1 до 10.
    43 +
    44 +### Выходные данные
    45 +
    46 +Номер самой популярной задачи.
    47 +
    48 +### Примеры
    49 +
    50 +| Ввод | Вывод |
    51 +|---|---|
    52 +| `7`<br>`3 1 3 7 1 3 2` | `3` |
    53 +| `4`<br>`5 2 5 2` | `2` |
    54 +
    55 +> [!NOTE]
    56 +> Заведите массив счётчиков `int cnt[11] = {0};` и для каждого числа `x` делайте `cnt[x]++`. Индекс 0 не используется — так номера задач совпадают с индексами.
    57 +
    58 +---
    59 +
    60 +## Задача 3. Хороший массив
    61 +
    62 +### Условие
    63 +
    64 +Массив называется **хорошим**, если каждое число `x`, которое в нём встречается, встречается ровно `x` раз. Например, массив `3 1 3 2 3 2` хороший: единица встречается один раз, двойка — два, тройка — три.
    65 +
    66 +Определите, является ли данный массив хорошим.
    67 +
    68 +### Входные данные
    69 +
    70 +В первой строке вводится число `N` (`1 ≤ N ≤ 1000`). Во второй строке — `N` чисел от 1 до 1000.
    71 +
    72 +### Выходные данные
    73 +
    74 +`YES`, если массив хороший, иначе `NO`.
    75 +
    76 +### Примеры
    77 +
    78 +| Ввод | Вывод |
    79 +|---|---|
    80 +| `6`<br>`3 1 3 2 3 2` | `YES` |
    81 +| `3`<br>`2 2 2` | `NO` |
    82 +| `1`<br>`1` | `YES` |
    83 +
    84 +> [!TIP]
    85 +> Сначала посчитайте, сколько раз встречается каждое число: `cnt[a[i]]++`. Потом пройдите по массиву ещё раз и проверьте `cnt[a[i]] == a[i]` для каждого элемента. Обратите внимание: здесь нужны два прохода, поэтому числа придётся сохранить в массив.
    86 +
    87 +---
    88 +
    89 +## Задача 4. Все вхождения подстроки
    90 +
    91 +### Условие
    92 +
    93 +Даны строка `s` и образец `t`. Выведите позиции (считая с нуля) всех вхождений `t` в `s`. Вхождения могут перекрываться.
    94 +
    95 +### Входные данные
    96 +
    97 +Две строки из строчных латинских букв, каждая на отдельной строке.
    98 +
    99 +### Выходные данные
    100 +
    101 +Позиции всех вхождений через пробел в порядке возрастания. Если вхождений нет, выведите `-1`.
    102 +
    103 +### Примеры
    104 +
    105 +| Ввод | Вывод |
    106 +|---|---|
    107 +| `abababa`<br>`aba` | `0 2 4` |
    108 +| `hello`<br>`ll` | `2` |
    109 +| `hello`<br>`xyz` | `-1` |
    110 +
    111 +> [!TIP]
    112 +> Перебирайте начальную позицию `i` от 0, пока `i + t.size() <= s.size()`, и сравнивайте `s.substr(i, t.size()) == t`. Другой способ — `s.find(t, from)`: второй аргумент задаёт, с какой позиции искать.
    113 +
    114 +---
    115 +
    116 +## Задача 5. Минимальное окно
    117 +
    118 +### Условие
    119 +
    120 +Дана строка из строчных латинских букв. Найдите длину самой короткой подстроки, которая содержит **все различные буквы**, встречающиеся в строке.
    121 +
    122 +### Входные данные
    123 +
    124 +Одна строка длиной до 10⁵ символов.
    125 +
    126 +### Выходные данные
    127 +
    128 +Одно число — длина минимального окна.
    129 +
    130 +### Примеры
    131 +
    132 +| Ввод | Вывод |
    133 +|---|---|
    134 +| `aabcbcdbca` | `4` |
    135 +| `aaaa` | `1` |
    136 +| `abc` | `3` |
    137 +
    138 +> [!NOTE]
    139 +> В первой строке четыре различные буквы `a`, `b`, `c`, `d`. Самое короткое окно, которое их все содержит, — `dbca`, его длина 4.
    140 +
    141 +> [!TIP]
    142 +> Задача на **метод двух указателей**. Двигайте правую границу `r` и считайте буквы в окне массивом `int cnt[26]`. Как только в окне есть все нужные буквы, сдвигайте левую границу `l`, пока это условие не нарушится, и обновляйте ответ. Каждая граница проходит строку один раз, поэтому решение работает быстро даже для 10⁵ символов.
  • Показать разницуСкрыть разницу
    1 +# ✅ Обязательные задачи (LMS)
    2 +
    3 +> Эти задачи нужно решить и сдать в LMS.
    4 +
    5 +---
    6 +
    7 +## Задача 1. Рассадка участников
    8 +
    9 +### Условие
    10 +
    11 +На олимпиаду по информатике пришло `N` участников. Известно, в какой школе учится каждый из них. В компьютерном классе `N` компьютеров стоят в одну линию вдоль стены.
    12 +
    13 +Определите, можно ли рассадить участников так, чтобы никакие два участника из одной школы не сидели рядом.
    14 +
    15 +### Входные данные
    16 +
    17 +В первой строке вводится число `N` (`1 ≤ N ≤ 1000`). Во второй строке — `N` натуральных чисел, номера школ участников.
    18 +
    19 +### Выходные данные
    20 +
    21 +`YES`, если рассадить можно, иначе `NO`.
    22 +
    23 +### Примеры
    24 +
    25 +**Ввод:**
    26 +
    27 +```text
    28 +5
    29 +1 1 1 2 3
    30 +```
    31 +
    32 +**Вывод:**
    33 +
    34 +```text
    35 +YES
    36 +```
    37 +
    38 +**Ввод:**
    39 +
    40 +```text
    41 +4
    42 +1 1 1 2
    43 +```
    44 +
    45 +**Вывод:**
    46 +
    47 +```text
    48 +NO
    49 +```
    50 +
    51 +> [!NOTE]
    52 +> В первом примере подойдёт рассадка `1 2 1 3 1`. Во втором примере троих участников из школы 1 на четыре места без соседства не посадить.
    53 +
    54 +> [!TIP]
    55 +> Посчитайте, сколько участников из самой «многочисленной» школы. Рассадить можно, если это количество не больше `(N + 1) / 2`.
    56 +
    57 +---
    58 +
    59 +## Задача 2. Туристический маршрут
    60 +
    61 +### Условие
    62 +
    63 +Дана карта гор Авалона: высоты точек при движении с запада на восток. Туристический маршрут — это отрезок подряд идущих точек, на котором есть подъём и спуск: внутри маршрута найдётся точка, которая **строго выше** и начальной, и конечной точки.
    64 +
    65 +Найдите длину самого короткого туристического маршрута. Длина маршрута — количество точек в нём.
    66 +
    67 +### Входные данные
    68 +
    69 +В первой строке вводится число `N` — количество точек. Во второй строке — `N` целых чисел, высоты точек.
    70 +
    71 +Гарантируется, что хотя бы один туристический маршрут существует.
    72 +
    73 +### Выходные данные
    74 +
    75 +Одно число — минимальная длина маршрута.
    76 +
    77 +### Пример
    78 +
    79 +**Ввод:**
    80 +
    81 +```text
    82 +4
    83 +15 20 20 10
    84 +```
    85 +
    86 +**Вывод:**
    87 +
    88 +```text
    89 +4
    90 +```
    91 +
    92 +> [!NOTE]
    93 +> Отрезки `15 20 20` и `20 20 10` не подходят: высота 20 не строго больше конца 20. Подходит только весь маршрут `15 20 20 10` — его длина 4.
    94 +
    95 +> [!TIP]
    96 +> Переберите все пары концов `i < j`, найдите максимум на отрезке `[i, j]` и проверьте, что он строго больше `a[i]` и `a[j]`. Начальное значение ответа возьмите заведомо большим, например `N + 1`.
    97 +
    98 +---
    99 +
    100 +## Задача 3. Близость геномов
    101 +
    102 +### Условие
    103 +
    104 +Геном — строка из заглавных латинских букв. **Пары соседних оснований** — это все подстроки длины 2. Степень близости первого генома второму — количество пар первого генома, которые встречаются во втором геноме.
    105 +
    106 +Если одна и та же пара встречается в первом геноме несколько раз, каждое вхождение считается отдельно.
    107 +
    108 +### Входные данные
    109 +
    110 +Две строки `s1` и `s2`, каждая на отдельной строке.
    111 +
    112 +### Выходные данные
    113 +
    114 +Одно число — степень близости первого генома второму.
    115 +
    116 +### Пример
    117 +
    118 +**Ввод:**
    119 +
    120 +```text
    121 +ABBACAB
    122 +BCABB
    123 +```
    124 +
    125 +**Вывод:**
    126 +
    127 +```text
    128 +4
    129 +```
    130 +
    131 +> [!NOTE]
    132 +> Пары первого генома: `AB`, `BB`, `BA`, `AC`, `CA`, `AB`. Пары второго: `BC`, `CA`, `AB`, `BB`. Во втором геноме встречаются `AB`, `BB`, `CA` и ещё раз `AB` — всего 4.
    133 +
    134 +> [!TIP]
    135 +> Пару выделяйте через `s1.substr(i, 2)`, а наличие во второй строке проверяйте через `s2.find(pair) != string::npos`.
    136 +
    137 +---
    138 +
    139 +## Задача 4. Срез строки
    140 +
    141 +### Условие
    142 +
    143 +Дана строка `S` и три целых числа `start`, `end`, `step`. Постройте **срез** строки: символы с индексами `start`, `start + step`, `start + 2·step`, ..., строго меньшими `end`. Индексы считаются с нуля.
    144 +
    145 +Если `end` больше длины строки, срез идёт до конца строки.
    146 +
    147 +### Входные данные
    148 +
    149 +В первой строке — строка `S` без пробелов. Во второй строке — три целых числа `start`, `end`, `step` (`0 ≤ start`, `0 ≤ end`, `step ≥ 1`).
    150 +
    151 +### Выходные данные
    152 +
    153 +Получившаяся строка. Если в срез не попал ни один символ, выведите пустую строку.
    154 +
    155 +### Пример
    156 +
    157 +**Ввод:**
    158 +
    159 +```text
    160 +abcdefg
    161 +1 6 2
    162 +```
    163 +
    164 +**Вывод:**
    165 +
    166 +```text
    167 +bdf
    168 +```
    169 +
    170 +> [!NOTE]
    171 +> Берутся символы с индексами 1, 3, 5: `b`, `d`, `f`. Следующий индекс 7 уже не меньше 6, поэтому срез заканчивается. Так же работает срез `S[1:6:2]` в Python.
    172 +
    173 +---
    174 +
    175 +## Задача 5. Свободные купе
    176 +
    177 +### Условие
    178 +
    179 +В плацкартном вагоне 54 места, пронумерованных от 1 до 54. Вагон разбит на 9 купе.
    180 +
    181 +Первые 36 мест расположены по левую сторону от прохода: места 1–4 находятся в первом купе, места 5–8 — во втором, и так далее, места 33–36 — в девятом. По правую сторону от прохода — боковые места с номерами от 37 до 54, они нумеруются в противоположном направлении: места 37 и 38 стоят напротив девятого купе, а места 53 и 54 — напротив первого.
    182 +
    183 +Группа школьников едет на олимпиаду и хочет купить несколько подряд идущих купе целиком, вместе с прилегающими боковыми местами. Даны номера свободных мест. Определите, какое наибольшее число подряд идущих купе полностью свободно.
    184 +
    185 +### Входные данные
    186 +
    187 +В первой строке — число `N` (`0 ≤ N ≤ 54`), количество свободных мест. Далее `N` строк — номера свободных мест.
    188 +
    189 +### Выходные данные
    190 +
    191 +Одно число — наибольшее количество подряд идущих полностью свободных купе.
    192 +
    193 +### Пример
    194 +
    195 +**Ввод:**
    196 +
    197 +```text
    198 +12
    199 +5
    200 +6
    201 +3
    202 +4
    203 +8
    204 +7
    205 +51
    206 +9
    207 +10
    208 +54
    209 +1
    210 +52
    211 +```
    212 +
    213 +**Вывод:**
    214 +
    215 +```text
    216 +1
    217 +```
    218 +
    219 +> [!NOTE]
    220 +> Полностью свободно только второе купе: места 5, 6, 7, 8 и боковые 51, 52. В первом купе занято место 2, в третьем — места 11 и 12.
    221 +
    222 +> [!TIP]
    223 +> Отметьте свободные места в массиве флажков `bool freeSeat[55] = {false};`. Купе `i` (от 1 до 9) — это места `4*i - 3`, `4*i - 2`, `4*i - 1`, `4*i` и боковые `55 - 2*i`, `56 - 2*i`. Затем найдите самую длинную серию свободных купе.
    224 +
    225 +---
    226 +
    227 +## Задача 6. Операции со строками
    228 +
    229 +### Условие
    230 +
    231 +Даны три строки. Над каждой строкой разрешается выполнять две операции:
    232 +
    233 +- заменить любой символ на два таких же символа (`a` → `aa`);
    234 +- заменить два подряд идущих одинаковых символа на один (`aa` → `a`).
    235 +
    236 +С помощью этих операций нужно сделать все три строки равными одной и той же строке `S`, причём `S` должна быть как можно короче. Если сделать строки равными невозможно, выведите `IMPOSSIBLE`.
    237 +
    238 +### Входные данные
    239 +
    240 +Три строки из строчных латинских букв, каждая на отдельной строке.
    241 +
    242 +### Выходные данные
    243 +
    244 +Строка `S` или слово `IMPOSSIBLE`.
    245 +
    246 +### Примеры
    247 +
    248 +**Ввод:**
    249 +
    250 +```text
    251 +aab
    252 +abb
    253 +ab
    254 +```
    255 +
    256 +**Вывод:**
    257 +
    258 +```text
    259 +ab
    260 +```
    261 +
    262 +**Ввод:**
    263 +
    264 +```text
    265 +ab
    266 +ba
    267 +ab
    268 +```
    269 +
    270 +**Вывод:**
    271 +
    272 +```text
    273 +IMPOSSIBLE
    274 +```
    275 +
    276 +> [!TIP]
    277 +> Операции меняют только длину «блоков» одинаковых символов, но не их порядок. Сожмите каждую строку, оставив по одному символу из каждого блока (`aabbbcc` → `abc`). Если все три сжатые строки равны — это и есть ответ. Сжатие удобно оформить функцией `string compress(string s)`.
  • Показать разницуСкрыть разницу
    1 +# 🧑‍🏫 Практика
    2 +
    3 +> Задачи, которые решаем на занятиях.
    4 +
    5 +---
    6 +
    7 +## Задача 1. Количество гласных букв
    8 +
    9 +### Условие
    10 +
    11 +Дана строка, состоящая из латинских букв (строчных и заглавных) и пробелов. Определите, сколько в ней гласных букв.
    12 +
    13 +Гласными считаются буквы `A`, `E`, `I`, `O`, `U`, `Y` и соответствующие строчные `a`, `e`, `i`, `o`, `u`, `y`.
    14 +
    15 +### Входные данные
    16 +
    17 +Одна строка.
    18 +
    19 +### Выходные данные
    20 +
    21 +Одно число — количество гласных букв.
    22 +
    23 +### Примеры
    24 +
    25 +**Ввод:**
    26 +
    27 +```text
    28 +Hello World
    29 +```
    30 +
    31 +**Вывод:**
    32 +
    33 +```text
    34 +3
    35 +```
    36 +
    37 +**Ввод:**
    38 +
    39 +```text
    40 +Programming
    41 +```
    42 +
    43 +**Вывод:**
    44 +
    45 +```text
    46 +3
    47 +```
    48 +
    49 +> [!NOTE]
    50 +> В строке есть пробел, поэтому читать её нужно через `getline(cin, text)`: `cin >> text` прочитает только `Hello`. Дальше перебираем символы `text[i]` и сравниваем каждый с гласными через `||`.
    51 +
    52 +---
    53 +
    54 +## Задача 2. Самая длинная серия
    55 +
    56 +### Условие
    57 +
    58 +Дан массив целых чисел. Найдите длину самой длинной последовательности одинаковых подряд идущих элементов.
    59 +
    60 +### Входные данные
    61 +
    62 +В первой строке вводится число `N` (`1 ≤ N ≤ 1000`). Во второй строке — `N` целых чисел.
    63 +
    64 +### Выходные данные
    65 +
    66 +Одно число — длина самой длинной серии.
    67 +
    68 +### Пример
    69 +
    70 +**Ввод:**
    71 +
    72 +```text
    73 +10
    74 +4 4 4 2 2 7 7 7 7 1
    75 +```
    76 +
    77 +**Вывод:**
    78 +
    79 +```text
    80 +4
    81 +```
    82 +
    83 +> [!NOTE]
    84 +> Серии: `4 4 4` (длина 3), `2 2` (2), `7 7 7 7` (4), `1` (1). Самая длинная — 4. Сравнивайте `a[i]` с `a[i - 1]`, поэтому цикл начинается с `i = 1`, а начальные `current` и `max_len` равны 1: даже один элемент — это серия.
    85 +
    86 +---
    87 +
    88 +## Задача 3. Лишняя буква
    89 +
    90 +### Условие
    91 +
    92 +Даны две строки. Определите, сколько **различных** букв встречается в первой строке, но отсутствует во второй.
    93 +
    94 +### Входные данные
    95 +
    96 +Две строки из строчных латинских букв, каждая на отдельной строке.
    97 +
    98 +### Выходные данные
    99 +
    100 +Одно число.
    101 +
    102 +### Пример
    103 +
    104 +**Ввод:**
    105 +
    106 +```text
    107 +abracadabra
    108 +bar
    109 +```
    110 +
    111 +**Вывод:**
    112 +
    113 +```text
    114 +2
    115 +```
    116 +
    117 +> [!NOTE]
    118 +> В первой строке есть буквы `a`, `b`, `r`, `c`, `d`, во второй — только `a`, `b`, `r`. Отсутствуют `c` и `d`. Чтобы не посчитать одну букву дважды, отмечайте уже учтённые буквы в массиве `bool used[26] = {false};` по индексу `c - 'a'`.
    119 +
    120 +---
    121 +
    122 +## Задача 4. Самый частый символ
    123 +
    124 +### Условие
    125 +
    126 +Дана строка из строчных латинских букв. Определите символ, который встречается в ней чаще всего. Если таких символов несколько, выведите тот, который раньше стоит в алфавите.
    127 +
    128 +### Входные данные
    129 +
    130 +Одна строка.
    131 +
    132 +### Выходные данные
    133 +
    134 +Один символ.
    135 +
    136 +### Пример
    137 +
    138 +**Ввод:**
    139 +
    140 +```text
    141 +mississippi
    142 +```
    143 +
    144 +**Вывод:**
    145 +
    146 +```text
    147 +i
    148 +```
    149 +
    150 +> [!NOTE]
    151 +> Буквы `i` и `s` встречаются по 4 раза, но `i` раньше в алфавите. Подсчитайте частоты в массиве `int cnt[26] = {0};` и найдите индекс максимума. Сравнение строго `>`, а не `>=`: тогда при равенстве останется буква с меньшим индексом. Вывод: `char('a' + maxIdx)`.
    152 +
    153 +---
    154 +
    155 +## Задача 5. Локальные максимумы
    156 +
    157 +### Условие
    158 +
    159 +Дан массив целых чисел. Элемент называется **локальным максимумом**, если он строго больше обоих своих соседей. Первый и последний элементы локальными максимумами не считаются.
    160 +
    161 +Выведите количество локальных максимумов.
    162 +
    163 +### Входные данные
    164 +
    165 +В первой строке вводится число `N` (`1 ≤ N ≤ 1000`). Во второй строке — `N` целых чисел.
    166 +
    167 +### Выходные данные
    168 +
    169 +Одно число — количество локальных максимумов.
    170 +
    171 +### Пример
    172 +
    173 +**Ввод:**
    174 +
    175 +```text
    176 +7
    177 +1 5 2 4 3 6 1
    178 +```
    179 +
    180 +**Вывод:**
    181 +
    182 +```text
    183 +3
    184 +```
    185 +
    186 +> [!NOTE]
    187 +> Локальные максимумы — 5, 4 и 6. Цикл идёт от `i = 1` до `i < n - 1`, иначе обращение к `a[i - 1]` или `a[i + 1]` выйдет за границы массива. Если `N < 3`, цикл не выполнится ни разу и ответ равен 0.
  • Показать разницуСкрыть разницу
    1 +# 📘 Тема 1.6. Необходимый материал
    2 +
    3 +> Шпаргалка по массивам и строкам.
    4 +
    5 +---
    6 +
    7 +## 1. Зачем нужны массивы
    8 +
    9 +До сих пор числа обрабатывались «на лету»: считали — сразу использовали — забыли. Но иногда к элементу нужно вернуться: пройти по данным второй раз, сравнить соседей, отсортировать. Для этого данные нужно **хранить**.
    10 +
    11 +**Массив** — набор элементов **одного типа**, которые лежат в памяти подряд и доступны по номеру.
    12 +
    13 +**Итерируемые объекты** — структуры, элементы которых можно перебирать в цикле:
    14 +
    15 +| Структура | Пример | Особенность |
    16 +|---|---|---|
    17 +| массив | `int arr[5] = {1, 2, 3, 4, 5};` | фиксированный размер |
    18 +| строка | `string s = "Hello";` | последовательность символов |
    19 +| вектор | `vector<int> v = {10, 20, 30};` | размер может меняться |
    20 +
    21 +Термины:
    22 +
    23 +| Термин | Значение |
    24 +|---|---|
    25 +| **элемент** | одно значение в массиве |
    26 +| **индекс** | номер элемента, начинается с `0` |
    27 +| **размер** | количество элементов |
    28 +| **обход** | перебор всех элементов циклом |
    29 +
    30 +---
    31 +
    32 +## 2. Объявление и инициализация
    33 +
    34 +```cpp
    35 +тип имя[размер];
    36 +```
    37 +
    38 +```cpp
    39 +int a[100]; // 100 целых чисел, значения не заданы
    40 +int b[5] = {10, 20, 30, 40, 50};
    41 +int c[5] = {0}; // все элементы равны 0
    42 +int d[] = {3, 1, 4}; // размер 3 вычисляется сам
    43 +bool used[26] = {false}; // 26 флажков, все false
    44 +```
    45 +
    46 +> [!IMPORTANT]
    47 +> Размер массива должен быть константой. В олимпиадных задачах массив обычно объявляют с запасом по максимальному ограничению: если `N ≤ 1000`, пишут `int a[1000];` (или чуть больше), а реально используют первые `n` элементов.
    48 +
    49 +> [!WARNING]
    50 +> Локальный массив без инициализации (`int a[100];` внутри `main`) содержит «мусор». Если массив используется как счётчики, обязательно пишите `= {0}`.
    51 +
    52 +---
    53 +
    54 +## 3. Индексация
    55 +
    56 +- Первый элемент — `a[0]`.
    57 +- Последний элемент массива из `n` элементов — `a[n - 1]`.
    58 +
    59 +```cpp
    60 +int arr[5] = {10, 20, 30, 40, 50};
    61 +cout << arr[0] << endl; // 10
    62 +cout << arr[4] << endl; // 50
    63 +arr[2] = 99; // теперь {10, 20, 99, 40, 50}
    64 +```
    65 +
    66 +| Индекс | 0 | 1 | 2 | 3 | 4 |
    67 +|---|---|---|---|---|---|
    68 +| Значение | 10 | 20 | 30 | 40 | 50 |
    69 +
    70 +Почему с нуля? Индекс — это **смещение** от начала массива. Первый элемент лежит в самом начале, его смещение равно 0.
    71 +
    72 +> [!CAUTION]
    73 +> `arr[5]` для массива из пяти элементов — **выход за границы**. Компилятор это не проверяет: программа может выдать мусор, испортить соседние переменные или упасть.
    74 +
    75 +---
    76 +
    77 +## 4. Заполнение и вывод
    78 +
    79 +### С клавиатуры
    80 +
    81 +```cpp
    82 +int n;
    83 +cin >> n;
    84 +int a[1000];
    85 +for (int i = 0; i < n; i++) {
    86 + cin >> a[i];
    87 +}
    88 +```
    89 +
    90 +### По формуле
    91 +
    92 +```cpp
    93 +int a[10];
    94 +for (int i = 0; i < 10; i++) {
    95 + a[i] = i + 1; // 1, 2, ..., 10
    96 +}
    97 +```
    98 +
    99 +### Случайными числами
    100 +
    101 +```cpp
    102 +#include <cstdlib> // rand, srand
    103 +#include <ctime> // time
    104 +
    105 +srand(time(0)); // без этого rand() каждый раз даёт одно и то же
    106 +for (int i = 0; i < 10; i++) {
    107 + a[i] = rand() % 100 + 1; // от 1 до 100
    108 +}
    109 +```
    110 +
    111 +> [!NOTE]
    112 +> Случайные числа удобны, чтобы проверить свою программу на большом тесте. В решениях олимпиадных задач они не нужны.
    113 +
    114 +### Вывод
    115 +
    116 +```cpp
    117 +for (int i = 0; i < n; i++) {
    118 + cout << a[i] << " ";
    119 +}
    120 +cout << endl;
    121 +```
    122 +
    123 +---
    124 +
    125 +## 5. Шаблоны обработки массива
    126 +
    127 +### Минимум и максимум
    128 +
    129 +```cpp
    130 +int mn = a[0];
    131 +int mx = a[0];
    132 +for (int i = 1; i < n; i++) {
    133 + if (a[i] < mn) mn = a[i];
    134 + if (a[i] > mx) mx = a[i];
    135 +}
    136 +```
    137 +
    138 +> [!IMPORTANT]
    139 +> Начинайте с первого элемента массива, а не с нуля. Для массива `{-5, -10, -3}` начальное `mx = 0` даст ответ 0, хотя максимум равен −3.
    140 +
    141 +### Среднее значение
    142 +
    143 +```cpp
    144 +int sum = 0;
    145 +for (int i = 0; i < n; i++) {
    146 + sum += a[i];
    147 +}
    148 +double average = (double)sum / n;
    149 +```
    150 +
    151 +Без `(double)` получится целочисленное деление: `61 / 6 = 10`, а не `10.1667`.
    152 +
    153 +### Сравнение с соседями
    154 +
    155 +```cpp
    156 +// локальные максимумы: первый и последний элементы не проверяем
    157 +int cnt = 0;
    158 +for (int i = 1; i < n - 1; i++) {
    159 + if (a[i] > a[i - 1] && a[i] > a[i + 1]) {
    160 + cnt++;
    161 + }
    162 +}
    163 +```
    164 +
    165 +### Самая длинная серия одинаковых
    166 +
    167 +```cpp
    168 +int best = 1, current = 1;
    169 +for (int i = 1; i < n; i++) {
    170 + if (a[i] == a[i - 1]) current++;
    171 + else current = 1;
    172 + if (current > best) best = current;
    173 +}
    174 +```
    175 +
    176 +> [!WARNING]
    177 +> При обращении к `a[i - 1]` цикл начинается с `i = 1`, при обращении к `a[i + 1]` — заканчивается на `i < n - 1`. Иначе будет выход за границы.
    178 +
    179 +---
    180 +
    181 +## 6. Массив через указатель
    182 +
    183 +Имя массива — это адрес его первого элемента. Поэтому `a[i]` и `*(a + i)` — одно и то же.
    184 +
    185 +```cpp
    186 +int arr[5] = {10, 20, 30, 40, 50};
    187 +int* ptr = arr; // указатель на arr[0]
    188 +
    189 +cout << *ptr << endl; // 10
    190 +cout << *(ptr + 3) << endl; // 40
    191 +```
    192 +
    193 +Размер массива, объявленного в той же функции, можно узнать через `sizeof`:
    194 +
    195 +```cpp
    196 +int arr[] = {10, 5, 8, 20, 3, 15};
    197 +int size = sizeof(arr) / sizeof(arr[0]); // 6
    198 +```
    199 +
    200 +---
    201 +
    202 +## 7. Символы и ASCII
    203 +
    204 +Каждому символу соответствует числовой код по таблице **ASCII**.
    205 +
    206 +| Символ | Код |
    207 +|---|---|
    208 +| `' '` (пробел) | 32 |
    209 +| `'0'` ... `'9'` | 48 ... 57 |
    210 +| `'A'` ... `'Z'` | 65 ... 90 |
    211 +| `'a'` ... `'z'` | 97 ... 122 |
    212 +
    213 +Цифры и буквы идут подряд, поэтому с символами можно работать как с числами:
    214 +
    215 +```cpp
    216 +char ch = 'A';
    217 +cout << (int)ch << endl; // 65
    218 +cout << (char)97 << endl; // a
    219 +
    220 +int d = '7' - '0'; // 7 — символ-цифра в число
    221 +char c = '0' + 5; // '5' — число в символ-цифру
    222 +int idx = 'c' - 'a'; // 2 — номер буквы в алфавите
    223 +char letter = 'a' + 3; // 'd'
    224 +```
    225 +
    226 +### Подсчёт букв массивом
    227 +
    228 +```cpp
    229 +int cnt[26] = {0};
    230 +for (int i = 0; i < s.size(); i++) {
    231 + cnt[s[i] - 'a']++; // для строчных латинских букв
    232 +}
    233 +```
    234 +
    235 +> [!TIP]
    236 +> Приём `c - 'a'` превращает букву в индекс от 0 до 25. Так массив `cnt[26]` становится «таблицей частот» букв, а `bool used[26]` — набором отметок «буква уже встречалась».
    237 +
    238 +---
    239 +
    240 +## 8. Строки `string`
    241 +
    242 +`string` — строка из символов. Нужен `#include <string>`.
    243 +
    244 +```cpp
    245 +string s;
    246 +cin >> s; // одно слово (до пробела)
    247 +getline(cin, s); // вся строка, вместе с пробелами
    248 +```
    249 +
    250 +| Операция | Что делает | Пример для `s = "Hello"` |
    251 +|---|---|---|
    252 +| `s.size()`, `s.length()` | длина строки | `5` |
    253 +| `s[i]` | символ с индексом `i` | `s[1]` → `'e'` |
    254 +| `s.substr(start, len)` | подстрока длины `len` с позиции `start` | `s.substr(1, 3)` → `"ell"` |
    255 +| `s.find(t)` | позиция первого вхождения `t` | `s.find("l")` → `2` |
    256 +| `s.push_back(c)`, `s += c` | добавить символ в конец | `"Hello!"` |
    257 +| `s.append(t)`, `s += t` | добавить строку в конец | `"Hello World"` |
    258 +| `s.back()` | последний символ | `'o'` |
    259 +| `s.empty()` | пустая ли строка | `false` |
    260 +| `s == t`, `s < t` | сравнение строк | `s == "Hello"` → `true` |
    261 +| `s.compare(t)` | `0`, если равны; `<0` или `>0` иначе | `s.compare("Hello")` → `0` |
    262 +
    263 +### Перебор символов
    264 +
    265 +```cpp
    266 +for (int i = 0; i < s.size(); i++) {
    267 + cout << s[i] << " ";
    268 +}
    269 +```
    270 +
    271 +### Поиск подстроки
    272 +
    273 +```cpp
    274 +if (s.find("ab") != string::npos) {
    275 + cout << "found" << endl;
    276 +}
    277 +```
    278 +
    279 +> [!IMPORTANT]
    280 +> Если подстрока не найдена, `find` возвращает специальное значение `string::npos`. Сравнивайте именно с ним, а не с `-1`.
    281 +
    282 +> [!WARNING]
    283 +> - `substr(start, len)` — второй аргумент это **длина**, а не конечная позиция.
    284 +> - `cin >> s` читает только до пробела. Для строки с пробелами нужен `getline(cin, s)`.
    285 +> - Если перед `getline` был `cin >> n`, в потоке остался перевод строки. Пропустите его: `cin.ignore();`.
    286 +> - `s.size()` возвращает беззнаковое число. Для пустой строки `s.size() - 1` — это не −1, а огромное число. Пишите `i + 1 < s.size()` или приводите к `int`.
    287 +
    288 +---
    289 +
    290 +## 9. Строки `char[]`
    291 +
    292 +Строка в стиле языка C — массив символов, который заканчивается **нулевым символом** `'\0'`. Функции для неё лежат в `<cstring>`.
    293 +
    294 +```cpp
    295 +char s[100] = "Hello"; // H e l l o \0
    296 +```
    297 +
    298 +| Функция | Что делает |
    299 +|---|---|
    300 +| `strlen(s)` | длина строки |
    301 +| `strcpy(dest, src)` | копирует `src` в `dest` |
    302 +| `strcat(dest, src)` | дописывает `src` в конец `dest` |
    303 +| `strcmp(s1, s2)` | сравнивает строки: `0`, если равны |
    304 +| `strstr(s1, s2)` | ищет `s2` внутри `s1` |
    305 +
    306 +> [!NOTE]
    307 +> `string` удобнее и безопаснее: он сам знает свою длину и сам выделяет память. `char[]` нужно знать, чтобы читать чужой код, но в своих решениях используйте `string`.
    308 +
    309 +---
    310 +
    311 +## 10. Пример: палиндром
    312 +
    313 +Два индекса идут навстречу друг другу с краёв строки и сравнивают символы.
    314 +
    315 +```cpp
    316 +bool isPalindrome(const string& s) {
    317 + int left = 0;
    318 + int right = s.size() - 1;
    319 + while (left < right) {
    320 + if (s[left] != s[right]) {
    321 + return false;
    322 + }
    323 + left++;
    324 + right--;
    325 + }
    326 + return true;
    327 +}
    328 +```
    329 +
    330 +`const string& s` — передача по ссылке: строка не копируется, а `const` запрещает её менять.
    331 +
    332 +---
    333 +
    334 +## 11. Пример: пары соседних символов
    335 +
    336 +Задача «Инопланетный геном»: сколько пар соседних букв первой строки встречаются во второй строке.
    337 +
    338 +```cpp
    339 +string s1, s2;
    340 +cin >> s1 >> s2;
    341 +
    342 +int ans = 0;
    343 +for (int i = 0; i + 1 < s1.size(); i++) {
    344 + string pair = s1.substr(i, 2);
    345 + if (s2.find(pair) != string::npos) {
    346 + ans++;
    347 + }
    348 +}
    349 +cout << ans << endl;
    350 +```
    351 +
    352 +Для `s1 = "ABBACAB"` и `s2 = "BCABB"`: пары первой строки `AB, BB, BA, AC, CA, AB`, из них во второй встречаются `AB, BB, CA, AB` — ответ 4.
    353 +
    354 +---
    355 +
    356 +## 12. Типичные ошибки
    357 +
    358 +| ❌ Неправильно | ✅ Правильно |
    359 +|---|---|
    360 +| `a[n]` — последний элемент | `a[n - 1]` |
    361 +| `for (int i = 0; i <= n; i++)` для обхода массива | `for (int i = 0; i < n; i++)` |
    362 +| `int cnt[26];` и сразу `cnt[x]++` | `int cnt[26] = {0};` |
    363 +| `int mx = 0;` для максимума массива | `int mx = a[0];` |
    364 +| `a[i] > a[i - 1]` при `i = 0` | начинать цикл с `i = 1` |
    365 +| `sum / n` для среднего | `(double)sum / n` |
    366 +| `cin >> s` для строки с пробелами | `getline(cin, s)` |
    367 +| `s.find(t) == -1` | `s.find(t) == string::npos` |
    368 +| `s.substr(2, 5)` как «с 2 по 5» | `s.substr(start, len)` — второй аргумент длина |
    369 +| `s[i]` вместо `s[i] - '0'` для цифры | `s[i] - '0'` |
    370 +| `if (s = "YES")` | `if (s == "YES")` |
    371 +
    372 +---
    373 +
    374 +## 13. Шаблон программы
    375 +
    376 +```cpp
    377 +#include <iostream>
    378 +#include <string>
    379 +using namespace std;
    380 +
    381 +int main() {
    382 + int n;
    383 + cin >> n;
    384 +
    385 + int a[1000];
    386 + for (int i = 0; i < n; i++) {
    387 + cin >> a[i];
    388 + }
    389 +
    390 + // обработка массива
    391 +
    392 + // вывод ответа
    393 +
    394 + return 0;
    395 +}
    396 +```