Открывается в новой вкладке

Мы всегда на связи

Пишите в любое удобное время:
whatsappvktelegramMAX
Или задайте вопрос через форму:

Мы всегда на связи

Заявка принята!

Мы уже получили заявку и скоро свяжемся. Расскажите немного о ребёнке — так быстрее подберём группу (необязательно).

Спасибо!

Мы свяжемся с вами в ближайшее время.

Разбор школьного этапа ВсОШ по программированию — 2026

23.10.2026

Разбор школьного этапа ВсОШ по информатике 2026: для 9–11 класса

20 октября прошёл школьный этап олимпиады по информатике, профиль «программирование». В варианте для 9–11 класса было пять задач: две на аккуратный счёт и моделирование, остальные на комбинаторику и построение ответа. Методисты Юайти решили все пять и показывают, откуда берётся идея, сколько баллов можно было взять простым перебором и как написать полное решение на Python и C++.

Рядом с каждой задачей мы отметили, какому уровню наших курсов она соответствует. Важно: это наша оценка трудности идеи, а не официальная классификация!

Что было на школьном этапе олимпиады по программированию

Школьный этап ВсОШ по информатике проходит на платформе «Сириус.Курсы». Он проводится по четырём профилям, и каждый делится на три возрастные параллели: 5–6, 7–8 и 9–11 класс. Здесь разобраны задания профиля «программирование» для 9–11 класса.

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

Если вы искали ответы на олимпиаду школьного этапа 2026, здесь есть не только итоговые числа, но и объяснение, почему решение работает.


Задача 1. Доставка в Простоквашино

Темы: математика, реализация / моделирование.

Уровень относительно наших курсов: Python / C++ Start, ОлПрактика lvl 1.

Коротко об условии задачи

Робот едет от почты к дому с номером $k$. На каждый переход между соседними домами он тратит $a$ единиц энергии, а у каждого дома может подзарядиться на $b$ единиц.

Нужно определить минимальный начальный заряд, с которым робот сможет добраться до $k$-го дома.

Сколько энергии понадобится роботу?

Начнём с самого первого перехода. До первого дома ещё нет возможности подзарядиться, поэтому роботу обязательно нужно хотя бы $a$ единиц энергии.

А что происходит дальше?

После каждого перехода робот тратит $a$ единиц, но у дома может восстановить $b$.

Здесь возникают два случая:

  • Если $b\ge a$, зарядка полностью компенсирует расходы на дорогу. Роботу достаточно начальных $a$ единиц, сколько бы домов ни пришлось проехать.
  • Если $b<a$, зарядка возвращает лишь часть потраченной энергии. После каждого следующего перехода робот теряет из первоначального запаса ещё $a-b$ единиц.

Посмотрим на второй случай подробнее.

Сколько дополнительной энергии нужно взять с собой?

Пусть

$$a=5,\qquad b=3,\qquad k=4.$$

Роботу нужно проехать четыре участка. На каждом он тратит 5 единиц, а зарядка возвращает только 3.

Получается, что после каждого такого перехода и подзарядки заряд уменьшается на

$$a-b=5-3=2.$$

Но первый переход особенный: его мы должны полностью обеспечить начальным зарядом.

Остаются ещё три перехода, каждый из которых потребует дополнительно по 2 единицы:

$$5+2+2+2=\boxed{11}.$$

Проверим, что 11 единиц действительно хватит.

Изменение заряда робота от почты до четвёртого дома

Если бы робот начал с 10 единицами, к последнему переходу ему не хватило бы одной единицы энергии. Значит, 11 — действительно минимальный начальный заряд.

Как получить общую формулу?

Теперь объединим наши наблюдения.

Первый переход требует $a$ единиц энергии. После него остаётся ещё $k-1$ переходов.

Если зарядка восстанавливает меньше энергии, чем робот тратит на дорогу, на каждый такой переход нужно предусмотреть дополнительные $a-b$ единиц.

Поэтому:

$$\boxed{\text{answer}=\begin{cases} a, & b\ge a,\\[4pt] a+(a-b)(k-1), & b<a. \end{cases}}$$

Почему эта формула даёт минимальный заряд? Первый переход нельзя совершить с запасом меньше $a$, а каждый из оставшихся переходов при $b<a$ неизбежно уменьшает запас на $a-b$. Мы учли ровно всю необходимую энергию.

При этом не нужно моделировать поездку по всем домам: даже если $k$ очень велико, ответ вычисляется сразу.

Реализация

  1. Считаем $a$, $b$ и $k$ — расход энергии, величину подзарядки и номер конечного дома.
  2. Изначально положим answer = a. Столько энергии необходимо для первого перехода.
  3. Проверим, хватает ли зарядки. Если a > b, каждый из оставшихся k - 1 переходов требует дополнительно a - b единиц. Прибавим весь необходимый запас к ответу.
  4. Выведем минимальный заряд.

Python

a = int(input())
b = int(input())
k = int(input())

# Энергия для первого перехода
answer = a

# Дополнительный запас на оставшиеся переходы
if a > b:
    answer += (a - b) * (k - 1)

print(answer)

C++17

#include <iostream>
using namespace std;

int main() {
    long long a, b, k;
    cin >> a >> b >> k;

    // Энергия для первого перехода
    long long answer = a;

    // Дополнительный запас на оставшиеся переходы
    if (a > b) {
        answer += (a - b) * (k - 1);
    }

    cout << answer << '\n';
}

Сложность: $O(1)$ по времени и дополнительной памяти.


Задача 2. Места в автобусе

Темы: реализация / моделирование, арифметика, цикличность.

Уровень относительно наших курсов: Python / C++ Start, ОлПрактика lvl 2.

Коротко об условии задачи

В автобусе по четыре места в каждом ряду: два слева от прохода и два справа. Два друга купили билеты на места с номерами $x$ и $y$.

Нужно определить, насколько удобно они сидят друг относительно друга:

  1. Категория 1: в одном ряду, рядом друг с другом, по одну сторону прохода.
  2. Категория 2: в одном ряду, по разные стороны прохода, но оба возле него.
  3. Категория 3: в соседних рядах, по одну сторону прохода.
  4. Категория 4: все остальные случаи.

Номера мест могут достигать $10^9$, поэтому строить расположение всего автобуса не получится.

Как устроены места в автобусе?

Сначала посмотрим на первые три ряда.

Расположение мест в первых трёх рядах автобуса

Обратите внимание: справа номера идут в обратном порядке. Например, в первом ряду у прохода находятся места 2 и 4, а не 2 и 3.

Посмотрим на несколько пар:

Места Категория Почему
1 и 2 1 Один ряд, одна сторона
2 и 4 2 Один ряд, оба у прохода
1 и 5 3 Соседние ряды, одна сторона
1 и 8 4 Ни одно условие не выполнено

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

Как найти ряд по номеру места?

Каждый ряд содержит четыре последовательных номера:

  • Первый: 1, 2, 3, 4.
  • Второй: 5, 6, 7, 8.
  • Третий: 9, 10, 11, 12.

Удобно перейти к нумерации с нуля. Вычтем из номера места единицу — тогда ряды будут начинаться с номеров 0, 4, 8 и так далее.

Номер ряда, считая с нуля, получим целочисленным делением:

$$\boxed{row=(x-1)\mathbin{//}4}.$$

Например, места 6 и 8 находятся в одном ряду, поскольку:

$$(6-1)//4=1,\qquad (8-1)//4=1.$$

А как определить сторону прохода?

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

Например, места 2 и 6 занимают одинаковое положение в разных рядах:

$$(2-1)\bmod4=1,\qquad (6-1)\bmod4=1.$$

Вычитаем единицу, поскольку ранее перешли к нумерации с нуля.

Получается, деление на 4 даёт номер ряда, а остаток от деления на 4 — положение места внутри ряда:

Остаток 0 1 2 3
Сторона Левая Левая Правая Правая

Поскольку первые два остатка соответствуют левой стороне, а следующие два — правой, достаточно разделить остаток на 2:

$$\boxed{side=((x-1)\bmod4)\mathbin{//}2}.$$

  • side = 0 — слева от прохода.
  • side = 1 — справа от прохода.

Осталось научиться определять, находится ли место возле прохода.

Посмотрим на схему: возле прохода находятся места 2, 4, 6, 8, 10, 12 и так далее.

Все эти номера чётные! Поэтому достаточно проверить:

$$\boxed{x\bmod2=0}.$$

Теперь у нас есть всё необходимое для определения категории.

Соберём решение

Для каждого места вычислим его ряд и сторону прохода. Затем проверим категории по порядку:

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

Проверять условия будем именно в таком порядке.

Реализация

  1. Считаем номера двух мест x и y.
  2. Найдём ряды rx и ry с помощью целочисленного деления на 4 после вычитания единицы.
  3. Определим стороны прохода sx и sy через остаток от деления на 4. Здесь 0 обозначает левую сторону, 1 — правую.
  4. Проверим три категории по порядку. Для второй категории используем чётность номеров, для третьей — разницу между номерами рядов.
  5. Если ни одно условие не выполнено, выведем категорию 4.

Python

x = int(input())
y = int(input())

# Ряды и стороны прохода
rx = (x - 1) // 4
ry = (y - 1) // 4

sx = ((x - 1) % 4) // 2
sy = ((y - 1) % 4) // 2

if rx == ry and sx == sy:
    print(1)
elif rx == ry and x % 2 == 0 and y % 2 == 0:
    print(2)
elif abs(rx - ry) == 1 and sx == sy:
    print(3)
else:
    print(4)

C++17

#include <iostream>
#include <cstdlib>
using namespace std;

int main() {
    int x, y;
    cin >> x >> y;

    // Ряды и стороны прохода
    int rx = (x - 1) / 4;
    int ry = (y - 1) / 4;

    int sx = ((x - 1) % 4) / 2;
    int sy = ((y - 1) % 4) / 2;

    if (rx == ry && sx == sy) {
        cout << 1 << '\n';
    } else if (rx == ry && x % 2 == 0 && y % 2 == 0) {
        cout << 2 << '\n';
    } else if (abs(rx - ry) == 1 && sx == sy) {
        cout << 3 << '\n';
    } else {
        cout << 4 << '\n';
    }
}

Сложность: $O(1)$ по времени и дополнительной памяти — выполняется фиксированное количество арифметических операций и проверок.


Задача 3. Три Кирилла и их рост

Темы: математика, комбинаторика, подсчёт, арифметическая прогрессия.

Уровень относительно наших курсов: Python / C++ Start, ОлПрактика lvl 4.

Коротко об условии задачи

Нужно посчитать количество троек положительных целых чисел $a,b,c$, для которых:

$$a\le b\le c,\qquad a+b+c=n.$$

При этом $n\le 2\cdot10^9$, поэтому перебирать все тройки не получится.

Решение за $O(1)$

Найдём число вариантов для фиксированного $a$, а затем вычислим их сумму без перебора.

Если первый Кирилл имеет рост $a$, то рост третьего Кирилла определяется через $a$ и $b$:

$$c=n-a-b.$$

Из условия $b\le c$ получаем:

$$b\le n-a-b \quad\Longrightarrow\quad b\le\left\lfloor\frac{n-a}{2}\right\rfloor.$$

При этом $b\ge a$. Значит, возможные значения второго роста:

$$a,\ a+1,\ \ldots,\ \left\lfloor\frac{n-a}{2}\right\rfloor.$$

Обозначим их количество через $N(a)$. Тогда

$$\boxed{ N(a)= \left\lfloor\frac{n-a}{2}\right\rfloor-a+1 = \left\lfloor\frac{n-3a}{2}\right\rfloor+1 }.$$

Третий рост уже однозначно определяется как $c=n-a-b$.

Пример для $n=9$

$a$ Возможные значения $b$ $N(a)$
1 1, 2, 3, 4 4
2 2, 3 2
3 3 1

Количество допустимых значений b при фиксированном a для n=9

Ответ:

$$4+2+1=7.$$

Как вычислить сумму без цикла?

Поскольку $a\le b\le c$, выполняется $3a\le n$. Обозначим

$$m=\left\lfloor\frac n3\right\rfloor.$$

Первый рост меняется от $1$ до $m$, поэтому ответ равен

$$\left\lfloor\frac{n-3}{2}\right\rfloor+ \left\lfloor\frac{n-6}{2}\right\rfloor+ \ldots+ \left\lfloor\frac{n-3m}{2}\right\rfloor+m.$$

Последнее $+m$ появилось из единицы, которую мы добавляли для каждого значения $a$.

Сумма числителей — арифметическая прогрессия:

$$S=(n-3)+(n-6)+\ldots+(n-3m) =mn-\frac{3m(m+1)}2.$$

Однако целочисленное деление нужно учитывать для каждого слагаемого отдельно. Перед делением нечётного числа на $2$ можно вычесть из него единицу. Поэтому, если среди чисел $n-3a$ встречается $\mathit{odd}$ нечётных, получаем

$$\boxed{\mathit{answer}=\frac{S-\mathit{odd}}2+m}.$$

Осталось посчитать $\mathit{odd}$. Число $n-3a$ нечётно тогда и только тогда, когда $n$ и $a$ имеют разную чётность:

  • если $n$ чётно, нужны нечётные $a$, поэтому $$\mathit{odd}=\left\lfloor\frac{m+1}{2}\right\rfloor;$$
  • если $n$ нечётно, нужны чётные $a$, поэтому $$\mathit{odd}=\left\lfloor\frac m2\right\rfloor.$$

Проверим формулу для $n=9$

$$m=3, \qquad S=6+3+0=9, \qquad \mathit{odd}=1.$$

Тогда

$$\frac{9-1}{2}+3=7.$$

Реализация

C++17

#include <iostream>
using namespace std;

int main() {
    long long n;
    cin >> n;

    long long m = n / 3;

    // Сумма чисел n - 3, n - 6, ..., n - 3m.
    long long sum = m * n - 3 * m * (m + 1) / 2;

    // Количество нечётных чисел в этой сумме.
    long long odd;
    if (n % 2 == 0) {
        odd = (m + 1) / 2;
    } else {
        odd = m / 2;
    }

    long long answer = (sum - odd) / 2 + m;
    cout << answer << '\n';
}

Сложность: $O(1)$ по времени и дополнительной памяти.

Все вычисления выполняем в типе long long. При максимальном $n$ ответ равен $333333333333333333$.


Задача 4. Очередь на заправку

Темы: реализация / моделирование, линейный проход, работа со временем.

Уровень относительно наших курсов: Python / C++ Start, ОлПрактика lvl 2.

Коротко об условии задачи

На заправке работают две колонки: одна для машин с горловиной бензобака слева, другая — справа.

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

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

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

Как движется очередь?

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

Можно ли тогда сразу отправлять каждую машину на свободную колонку?

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

Рассмотрим четыре машины:

$$-3,\quad -2,\quad +4,\quad -1.$$

Разберём, что происходит.

  1. Первая машина едет налево и заправляется с 0-й до 3-й минуты.
  2. Вторая тоже едет налево. Колонка занята, поэтому она начинает в момент 3 и заканчивает в момент 5.
  3. Третья едет направо. Правая колонка свободна с самого начала, но третья машина должна дождаться, пока вторая заедет на левую. Поэтому она начинает в момент 3 и заканчивает в момент 7.
  4. Четвёртая едет налево. Предыдущая машина уже начала заправку, но левая колонка освободится только в момент 5. Четвёртая начинает в 5 и заканчивает в 6.

Временная диаграмма работы двух колонок

Заметим интересную деталь: четвёртая машина закончила в момент 6, но третья продолжает заправляться до момента 7.

Поэтому ответ — 7 минут, а не 6. Нам нужно дождаться окончания работы обеих колонок.

Как определить момент начала заправки?

Для каждой машины важно знать два момента:

  • Когда предыдущая машина начала заправляться — раньше этого момента нельзя продвигаться по очереди.
  • Когда освободится нужная колонка — раньше этого момента нельзя занять её.

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

Для этого будем хранить всего три переменные:

  • prev — время начала заправки предыдущей машины;
  • left — время освобождения левой колонки;
  • right — время освобождения правой колонки.

Если машина едет налево:

$$\boxed{start=\max(prev,left)}.$$

Если направо:

$$\boxed{start=\max(prev,right)}.$$

Например, для третьей машины из нашего примера правая колонка свободна с момента 0, но предыдущая машина начинает заправляться только в момент 3:

$$start=\max(3,0)=3.$$

После этого прибавляем длительность заправки, обновляем время освобождения выбранной колонки и запоминаем новый prev.

Получается, хранить всю очередь и расписание машин не нужно! Достаточно трёх переменных времени и последовательного прохода по машинам.

Реализация

  1. Создадим три переменные: prev, left и right. Изначально все равны нулю, поскольку обе колонки свободны.
  2. Прочитаем очередную машину. По знаку t определим нужную колонку, а d = abs(t) — длительность заправки.
  3. Найдём момент начала заправки. Возьмём максимум из prev и времени освобождения нужной колонки. Затем обновим время её освобождения, прибавив длительность заправки.
  4. Запомним начало заправки текущей машины в prev, чтобы следующая машина не могла начать раньше.
  5. Выведем ответ. После обработки всех машин возьмём максимум из left и right — именно тогда обе колонки закончат работу.

Python

n = int(input())

left = 0
right = 0
prev = 0

for i in range(n):
    t = int(input())
    d = abs(t)

    if t < 0:
        # Ждём освобождения левой колонки
        start = max(prev, left)
        left = start + d
    else:
        # Ждём освобождения правой колонки
        start = max(prev, right)
        right = start + d

    # Запоминаем начало заправки текущей машины
    prev = start

print(max(left, right))

C++17

#include <iostream>
#include <algorithm>
#include <cstdlib>
using namespace std;

int main() {
    int n;
    cin >> n;

    long long left = 0;
    long long right = 0;
    long long prev = 0;

    // Обрабатываем машины в порядке очереди
    for (int i = 0; i < n; i++) {
        long long t;
        cin >> t;

        long long d = abs(t);
        long long start;

        if (t < 0) {
            // Ждём освобождения левой колонки
            start = max(prev, left);
            left = start + d;
        } else {
            // Ждём освобождения правой колонки
            start = max(prev, right);
            right = start + d;
        }

        // Запоминаем начало заправки текущей машины
        prev = start;
    }

    cout << max(left, right) << '\n';
}

В C++ используем long long, поскольку суммарное время заправки может превышать диапазон int.

Сложность: $O(n)$ по времени — каждую машину обрабатываем один раз. Дополнительная память $O(1)$, поскольку храним только три момента времени.


Задача 5. Мост из отрезков

Темы: конструктив, чётность, геометрия, инварианты, реализация.

Уровень относительно наших курсов: Python / C++ Start, ОлПрактика lvl 4.

Коротко об условии задачи

Нужно построить мост из точки $(0,0)$ в точку $(x,y)$ ровно из $n$ единичных отрезков. Каждый отрезок должен быть горизонтальным или вертикальным, а сам мост не должен пересекать себя.

Если построить такой мост невозможно, нужно вывести $-1$. Иначе — координаты всех $n+1$ вершин.

Как понять, можно ли вообще добраться до цели?

Для начала забудем про самопересечения. Сколько шагов нужно хотя бы для того, чтобы добраться до точки $(x,y)$?

По горизонтали придётся пройти $|x|$ клеток, по вертикали — $|y|$. Получаем минимальную длину:

$$D=|x|+|y|.$$

Если $n<D$, шагов просто не хватит.

А что, если шагов больше? Например, вместо 6 нужно сделать 7?

Каждый лишний шаг в какую-либо сторону приходится компенсировать обратным движением. Поэтому удлинять путь можно только на чётное число шагов. Иначе до нужной точки не добраться.

Получаем два необходимых условия:

$$\boxed{n\ge D,\qquad (n-D)\bmod 2=0}.$$

Но достаточно ли их? Ведь мост ещё и не должен пересекать себя.

Как добавить лишние шаги и ничего не пересечь?

Рассмотрим пример:

$$n=12,\qquad x=4,\qquad y=2.$$

До точки $(4,2)$ кратчайший путь состоит из четырёх шагов вправо и двух вверх. Всего 6, а нам нужно 12.

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

А что, если не возвращаться по старому пути, а перенести его часть в сторону?

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

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

Если опустить горизонтальный участок ещё ниже, мост станет длиннее ещё на два шага.

Мост из отрезков: 6, 8, 10 и 12 шагов

Для нашего примера достаточно опустить горизонтальный участок на три клетки:

$$(0,0)\rightarrow(0,-3)\rightarrow(4,-3)\rightarrow(4,2).$$

Длина маршрута:

$$3+4+5=12.$$

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

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

Соберём всё в общее решение

У нас уже есть две полезные идеи: минимальное расстояние $D$ и способ добавлять к нему шаги парами.

Посчитаем, сколько таких пар нужно:

$$e=\frac{n-D}{2}.$$

Именно на $e$ клеток будем смещать горизонтальную часть маршрута.

В примере выше $D=6,\ n=12$, поэтому $e=3$.

Для произвольной точки $(x,y)$, если $x\ne0$, построим мост из трёх частей:

  1. Сначала отходим от цели на $e$ клеток по вертикали. Если $y>0$, идём вниз. Если $y<0$, вверх. При $y=0$ можно выбрать любое направление.
  2. Затем проходим $|x|$ клеток по горизонтали. Вправо при $x>0$, влево при $x<0$.
  3. Наконец, идём по вертикали к конечной точке. Потребуется $e+|y|$ шагов в направлении, противоположном первому участку.

Получается ровно:

$$e+|x|+(e+|y|)=D+2e=n.$$

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

А если координаты отрицательные?

Например, $n=9,\ x=-3,\ y=-2$.

Здесь $D=5$, значит, нужно добавить четыре шага, то есть $e=2$.

Поскольку цель находится ниже и левее старта, сначала отойдём вверх, затем пойдём влево и только потом вниз:

$$(0,0)\rightarrow(0,2)\rightarrow(-3,2)\rightarrow(-3,-2).$$

Длина: $2+3+4=9$. Всё работает по той же схеме.

А если $x=0$?

Например, нужно за 7 шагов попасть в $(0,3)$.

Теперь горизонтальный участок кратчайшего пути вообще отсутствует. Но мы можем поменять роли координат: вместо вертикального отклонения используем горизонтальное.

Получится:

$$(0,0)\rightarrow(-2,0)\rightarrow(-2,3)\rightarrow(0,3).$$

Длина: $2+3+2=7$.

Таким образом, конструкция работает и в этом случае. А если лишних шагов нет ($e=0$), просто строим кратчайший путь.

Реализация

  1. Проверим, существует ли мост. Вычислим $D=|x|+|y|$. Если $n<D$ или $n-D$ нечётно, выводим -1.
  2. Найдём количество лишних пар шагов: e = (n - d) // 2. Если x == 0, поменяем координаты местами, чтобы можно было использовать одну конструкцию для всех случаев.
  3. Определим направления движения. sx показывает, куда идти по горизонтали к нужному x, а sy — куда сначала отклониться по вертикали, в сторону от цели.
  4. Зададим три участка маршрута. Для каждого храним изменение координат за один шаг (dx, dy) и количество шагов (count): сначала отклонение, затем движение по горизонтали, затем возвращение к конечной точке.
  5. Выведем вершины по порядку. Начнём с (0, 0), после каждого шага обновим координаты и выведем их. Если ранее меняли координаты местами, при выводе восстановим исходный порядок.

Python

n = int(input())
x = int(input())
y = int(input())

d = abs(x) + abs(y)

if n < d or (n - d) % 2 != 0:
    print(-1)
else:
    e = (n - d) // 2

    # При x = 0 меняем роли координат
    swapped = (x == 0)
    if swapped:
        x, y = y, x

    # Направление к x
    if x > 0:
        sx = 1
    else:
        sx = -1

    # Направление отклонения от y
    if y >= 0:
        sy = -1
    else:
        sy = 1

    # (dx, dy, count) — сдвиг по координатам и число шагов
    # Отклонение на e, движение на |x|, возврат на e + |y|
    moves = [(0, sy, e), (sx, 0, abs(x)), (0, -sy, e + abs(y))]

    u = 0
    v = 0
    print(0, 0)

    # Проходим три участка маршрута
    for dx, dy, count in moves:
        # Строим по одному единичному отрезку
        for i in range(count):
            u += dx
            v += dy

            # Восстанавливаем порядок координат
            if swapped:
                print(v, u)
            else:
                print(u, v)

C++17

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
using namespace std;

int main() {
    int n, x, y;
    cin >> n >> x >> y;

    int d = abs(x) + abs(y);

    if (n < d || (n - d) % 2 != 0) {
        cout << -1 << '\n';
        return 0;
    }

    int e = (n - d) / 2;

    // При x = 0 меняем роли координат
    bool swapped = (x == 0);
    if (swapped) {
        swap(x, y);
    }

    // Направление к x
    int sx;
    if (x > 0) {
        sx = 1;
    } else {
        sx = -1;
    }

    // Направление отклонения от y
    int sy;
    if (y >= 0) {
        sy = -1;
    } else {
        sy = 1;
    }

    // Три участка: отклонение, движение к x, возврат
    // dx, dy — сдвиг за шаг, cnt — количество шагов
    vector<int> dx = {0, sx, 0};
    vector<int> dy = {sy, 0, -sy};
    vector<int> cnt = {e, abs(x), e + abs(y)};

    int u = 0, v = 0;
    cout << "0 0\n";

    // Последовательно проходим три участка маршрута
    for (int i = 0; i < 3; i++) {
        // На каждом участке делаем cnt[i] единичных шагов
        for (int j = 0; j < cnt[i]; j++) {
            u += dx[i];
            v += dy[i];

            // Выводим новую вершину после каждого шага
            if (swapped) {
                cout << v << ' ' << u << '\n';
            } else {
                cout << u << ' ' << v << '\n';
            }
        }
    }
}

Сложность: $O(n)$ по времени, поскольку нужно вывести все $n+1$ вершин. Дополнительная память — $O(1)$ в обоих решениях.

 

Подготовка к МЭ ВсОШ по программированию

с 26 октября
методисты ЮАЙТИ
Содержание
Развернуть
Свернуть
Занятие с репетитором — Юайти
Занятие с репетитором
по математике
и программированию
Записаться

Понравилась статья?

Подпишись на Телеграм школы, чтобы не пропустить новые статьи и новости
Telegram канал

Поможем подобрать обучение

Оставьте телефон. Мы перезвоним, поможем выбрать подходящие занятия и ответим на вопросы

Поможем подобрать обучение

Заявка принята.

Мы свяжемся с вами