Редакция для Улитка в колодце
Submitting an official solution before solving the problem yourself is a bannable offence.
1. Идея
Нужно определить, на какой день улитка впервые достигнет высоты не меньше H.
Наивно можно было бы день за днём считать её положение:
- днём улитка поднимается на
U, - ночью сползает на
D.
Но ограничения большие: H, U, D могут быть до 10^9, поэтому долго моделировать по дням нельзя.
Ключевая идея — не перебирать все дни, а сразу вычислить ответ по формуле.
2. Наблюдения
Наблюдение 1
Если за первый же день улитка поднимается на высоту H или выше, то ответ сразу 1.
То есть если U >= H, то улитка выберется в первый день.
Наблюдение 2
Если в какой-то день улитка ещё не выбралась, то после ночи её высота увеличивается на U - D.
Почему именно так?
- днём она поднимается на
U, - ночью сползает на
D, - итог за полный день и ночь:
U - D.
Так как по условию U > D, улитка всё-таки постепенно движется вверх.
Наблюдение 3
Последний день отличается от остальных.
В последний день улитка:
- начинает день на некоторой высоте,
- поднимается на
U, - если достигает
H, то сразу выбирается, - ночью уже не соскальзывает.
Значит удобно отдельно посчитать:
- сколько полных циклов "день + ночь" нужно сделать до последнего дня,
- а потом прибавить ещё один, последний день.
3. Алгоритм
Пусть первый случай U >= H уже обработан.
Тогда улитка не может выбраться в первый день, значит U < H.
Обозначим:
daily = U - D— чистый прирост за один полный день и ночь,need = H - U— сколько ещё не хватает до края после подъёма в последний день.
Теперь нужно понять, сколько дней улитка должна прожить до последнего дня.
Перед последним днём высота улитки утром должна быть такой, чтобы после подъёма на U она достигла H.
То есть утром последнего дня её высота должна быть не меньше H - U.
После каждого завершённого дня и ночи высота увеличивается на daily, значит надо найти минимальное число таких завершённых циклов, чтобы накопить хотя бы need.
Это количество равно:
ceil(need / daily)
Для целых чисел это считается так:
(need + daily - 1) / dailyв C++,(need + daily - 1) // dailyв Python.
Это число — количество дней до последнего дня. Тогда ответ:
days_before_last + 1
4. Почему это работает
Рассмотрим высоту улитки утром каждого дня.
- Утром первого дня высота равна
0. - Если улитка не выбралась в этот день, то после ночи её высота станет
U - D. - Если не выбралась и во второй день, то после второй ночи высота станет
2 * (U - D). - И так далее.
Значит после k полных циклов "день + ночь" высота утром следующего дня равна:
k * (U - D)
Чтобы в следующий день выбраться, нужно:
k * (U - D) + U >= H
Переносим U вправо:
k * (U - D) >= H - U
То есть нужно минимальное целое k, для которого это выполняется.
Это и есть:
ceil((H - U) / (U - D))
После этих k полных циклов наступает ещё один день, в который улитка выбирается.
Поэтому итоговый ответ:
k + 1
Если же U >= H, то формула для "дней до последнего" уже не нужна, потому что последний день — это сразу первый.
5. Сложность
Алгоритм выполняет только несколько арифметических операций.
- Время:
O(1) - Память:
O(1)
6. Код на C++17
#include <iostream>
using namespace std;
int main() {
long long H, U, D;
cin >> H >> U >> D;
if (U >= H) {
cout << 1 << '\n';
return 0;
}
long long daily = U - D;
long long need = H - U;
long long days_before_last = (need + daily - 1) / daily;
long long answer = days_before_last + 1;
cout << answer << '\n';
return 0;
}
7. Код на Python 3
H, U, D = map(int, input().split())
if U >= H:
print(1)
else:
daily = U - D
need = H - U
days_before_last = (need + daily - 1) // daily
print(days_before_last + 1)
Комментарии