55import java .io .InputStream ;
66import java .io .OutputStream ;
77
8+ /*
9+ Принцип работы алгоритма
10+ Используется дек фиксированного размера m, реализованный на массиве как кольцевой буфер.
11+ Храним:
12+ - a[] — массив ёмкости m;
13+ - head — индекс первого элемента дека;
14+ - tail — индекс позиции "после последнего" элемента дека;
15+ - size — текущее количество элементов.
16+
17+ Индексы head и tail двигаются по кругу: при выходе за границу массива переходят в начало/конец.
18+ Операции:
19+ - push_back(x): записать x в a[tail], сдвинуть tail вперёд по кругу, увеличить size.
20+ - push_front(x): сдвинуть head назад по кругу, записать x в a[head], увеличить size.
21+ - pop_front(): взять a[head], сдвинуть head вперёд, уменьшить size.
22+ - pop_back(): сдвинуть tail назад, взять a[tail], уменьшить size.
23+
24+ Корректность (почему работает)
25+ Поддерживаются инварианты:
26+ 1) size всегда в диапазоне [0..m].
27+ 2) head указывает на первый элемент (если size > 0).
28+ 3) tail указывает на позицию сразу после последнего элемента (если size > 0).
29+ 4) Элементы дека в порядке обхода лежат в a по циклу, начиная с head и длиной size.
30+
31+ Проверка по операциям:
32+ - push_back при size < m кладёт новый элемент ровно в позицию tail, затем tail сдвигается на следующую
33+ позицию по кругу, поэтому tail снова указывает на "после последнего", а порядок элементов сохраняется.
34+ - push_front при size < m сначала сдвигает head на предыдущую позицию по кругу и кладёт туда новый элемент,
35+ поэтому head начинает указывать на добавленный элемент (он становится первым), а порядок сохраняется.
36+ - pop_front при size > 0 читает первый элемент из a[head], затем сдвигает head вперёд, уменьшая size:
37+ новым первым становится следующий элемент, инварианты сохраняются.
38+ - pop_back при size > 0 сначала сдвигает tail назад (на позицию последнего элемента), читает его и уменьшает size:
39+ tail снова становится "после последнего", инварианты сохраняются.
40+
41+ Ошибки "error" выводятся только когда операция невозможна:
42+ - push_* при size == m (переполнение),
43+ - pop_* при size == 0 (пустой дек).
44+ В этих случаях состояние (head, tail, size) не меняется, что сохраняет инварианты.
45+
46+ Сложность
47+ Каждая операция дека выполняет константное число действий: O(1) по времени.
48+ Память: массив из m элементов и несколько целых переменных: O(m) по памяти.
49+ */
50+
851public class Deque {
952
1053 // -------------------- FAST INPUT --------------------
@@ -296,7 +339,7 @@ private static void test() throws Exception {
296339 )
297340 );
298341
299- // Емкость 1 + переполнение
342+ // Емкость 1 + переполнение + попытка pop из пустого
300343 assertEq (
301344 "error\n 1\n error\n " ,
302345 solveIO (
@@ -309,7 +352,7 @@ private static void test() throws Exception {
309352 )
310353 );
311354
312- // Проверка кольцевого перехода (wrap-around)
355+ // Wrap-around: head/tail должны корректно "перепрыгивать" границу массива
313356 assertEq (
314357 "1\n 4\n 2\n 3\n " ,
315358 solveIO (
0 commit comments