Редакция для Обратный отсчёт терминала


Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.

Автор: montes332

Разбор задачи «Обратный отсчёт терминала»

Идея задачи

Нам дано число n и количество операций k.

За одну операцию происходит одно из двух действий:

  • если последняя цифра числа не равна 0, число уменьшается на 1;
  • если последняя цифра равна 0, эта цифра удаляется, то есть число делится на 10.

Нужно узнать, какое число получится после ровно k таких операций.

Это задача на прямое моделирование процесса. Здесь не нужно искать сложную формулу или придумывать хитрую оптимизацию: достаточно аккуратно выполнить описанные в условии действия ровно k раз.


Как мыслить при решении

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

Значит, естественное решение такое:

  1. Повторить цикл k раз.
  2. Каждый раз смотреть на последнюю цифру числа.
  3. Если последняя цифра 0, делить число на 10.
  4. Иначе уменьшать число на 1.

Последнюю цифру числа удобно получать с помощью остатка от деления на 10:

  • n % 10 — последняя цифра;
  • n / 10 или n // 10 — удаление последней цифры.

Почему это работает

Потому что мы в точности повторяем процесс из условия.

На каждом шаге возможны только два случая:

  • последняя цифра не ноль — тогда нужно сделать n = n - 1;
  • последняя цифра ноль — тогда нужно сделать n = n / 10.

Если выполнить это ровно k раз, то мы получим ровно тот результат, который и требуется по условию.

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


Разберём пример

Пусть:

n = 512, k = 4

Тогда:

  1. 512 — последняя цифра 2, не ноль, получаем 511
  2. 511 — последняя цифра 1, не ноль, получаем 510
  3. 510 — последняя цифра 0, удаляем её, получаем 51
  4. 51 — последняя цифра 1, не ноль, получаем 50

Ответ: 50.


Оценка сложности

Мы выполняем ровно k операций.

Каждая операция занимает константное время, потому что мы делаем только:

  • проверку n % 10,
  • либо n -= 1,
  • либо деление на 10.

Итог:

  • Время: O(k)
  • Память: O(1)

Это очень эффективно.


Эталонное решение на C++

#include <iostream>
using namespace std;

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

    for (int i = 0; i < k; i++) {
        if (n % 10 == 0) {
            n /= 10;
        } else {
            n--;
        }
    }

    cout << n << '\n';
    return 0;
}
Пояснение к коду на C++
  • считываем n и k;
  • запускаем цикл на k шагов;
  • если последняя цифра равна нулю, удаляем её делением на 10;
  • иначе уменьшаем число на 1;
  • после цикла выводим результат.

Эталонное решение на Python

n, k = map(int, input().split())

for _ in range(k):
    if n % 10 == 0:
        n //= 10
    else:
        n -= 1

print(n)
Пояснение к коду на Python

Логика полностью такая же:

  • n % 10 даёт последнюю цифру;
  • n //= 10 удаляет последнюю цифру;
  • n -= 1 уменьшает число на единицу.

Типичные ошибки

1. Делить на 10 всегда, когда число оканчивается на 0, но забыть про остальные случаи

Некоторые участники обрабатывают только случай с нулём на конце и забывают, что иначе нужно просто вычесть 1.

2. Выполнить не k операций, а меньше

Например, остановиться, когда число стало маленьким. По условию нужно сделать ровно k операций.

3. Использовать вещественное деление

В Python нужно использовать именно //, а не /, потому что / делает вещественное деление.

Правильно:

n //= 10

Неправильно:

n /= 10
4. Пытаться придумать слишком сложное решение

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


Комментарии

Еще нет ни одного комментария.