Краткое описание: В этой статье мы подробно разберём задачу с условным номером 13140, которая часто встречается в онлайн‑тренировках по программированию. Мы рассмотрим формулировку, анализ требований, алгоритмический подход, пример реализации на языке Python и типичные ошибки, которые совершают новички.
Формулировка задачи
Дано:
- Последовательность целых чисел
a₁, a₂, …, aₙ(1 ≤ n ≤ 10⁵). - Каждое число находится в диапазоне от
-10⁹до10⁹.
Требуется:
- Найти самый длинный подпоследовательный отрезок, в котором разность между соседними элементами не превышает заданного порога
k(0 ≤ k ≤ 10⁹). - Вывести длину этого отрезка и его индексы
lиr(1‑based).
Если несколько отрезков имеют одинаковую максимальную длину, выводится тот, у которого l минимально.
Пример входных и выходных данных
Вход: 8 3 1 5 4 8 9 12 13 15 Выход: 5 2 6
Объяснение: отрезок [5, 4, 8, 9, 12] (индексы 2‑6) имеет длину 5, а разность между соседними элементами ≤ 3.
Алгоритмический анализ
Наивный подход
Перебрать все возможные отрезки [l, r] и проверять условие. Сложность O(n²) – слишком медленно для n = 10⁵.
Оптимальный подход – скользящее окно
Идея: поддерживать два указателя left и right, расширяя окно вправо, пока условие выполняется. Если разность становится > k, сдвигаем left вперёд.
Псевдокод:
left = 0 best_len = 1 best_l = 0 for right from 1 to n‑1: while a[right] ‒ a[right‑1] > k: left = right cur_len = right — left + 1 if cur_len > best_len: best_len = cur_len best_l = left
Сложность: O(n) по времени и O(1) по памяти.
Особенности реализации
- В условии важна абсолютная разность
|a[i]‑a[i‑1]|, а не только разность. - Для корректного сдвига окна необходимо проверять
whileдо тех пор, пока условие нарушено. - Индексы в выводе должны быть 1‑based, поэтому к найденным позициям прибавляем
+1.
Реализация на Python
def longest_segment(arr, k):
n = len(arr)
left = 0
best_len = 1
best_l = 0
for right in range(1, n):
# проверяем абсолютную разность
while abs(arr[right] ‒ arr[right — 1]) > k:
left = right
cur_len = right — left + 1
if cur_len > best_len:
best_len = cur_len
best_l = left
# переводим индексы в 1‑based
return best_len, best_l + 1, best_l + best_len
if __name__ == "__main__":
import sys
data = sys.stdin.read.strip.split
if not data:
sys.exit
n = int(data[0])
k = int(data[1])
a = list(map(int, data[2:2 + n]))
length, l, r = longest_segment(a, k)
print(length, l, r)
Пояснения к коду
- Функция
longest_segmentреализует скользящее окно. - Внутри цикла
whileмы «обнуляем» левый конец окна, если условие нарушено. - Переменные
best_lenиbest_lхранят текущий лучший результат. - В конце функции возвращаем длину и границы отрезка в требуемом формате.
Тестирование и отладка
Набор тестов
- Минимальный случай:
n=1. Ожидаем1 1 1. - Все элементы одинаковы:
k=0, массив[7,7,7,7]. Ожидаем4 1 4. - Разрыв в середине:
[1,2,10,11,12],k=2. Ожидаем3 3 5. - Большие числа: проверка на переполнение
int(Python без проблем).
Как искать ошибки
- Убедитесь, что
absиспользуется – иначе отрицательные разности «пропустятся». - Проверьте граничные условия: когда
rightпереходит в конец массива. - Сравните результат с «наивным» решением на небольших случайных тестах;
Часто задаваемые вопросы (FAQ)
Что делать, если k равно 0?
Тогда отрезок может включать только одинаковые подряд идущие элементы. Алгоритм работает без изменений.
Можно ли решить задачу за O(n log n)?
Да, используя структуру «многиминный набор» (multiset) и двоичный поиск, но это избыточно – линейный подход проще и быстрее.
Как адаптировать решение под язык C++?
Переписать цикл с двумя указателями, использовать std::abs и std::cin/std::cout. Сложность и логика остаются теми же.
Задача «Часть 13140 сво какая из задача» – типичный пример применения техники скользящего окна. Благодаря линейному проходу мы получаем решение, которое укладывается в ограничения по времени и памяти даже при максимальном размере входных данных.
Если у вас возникнут вопросы по реализации или вы захотите обсудить альтернативные подходы, пишите в комментариях. Мы будем рады помочь!
Контактная информация автора (частично скрыта)
Электронная почта: example@mail.com
Телефон: +7 (495) ‑‑