Форум программистов, компьютерный форум, киберфорум
Алгоритмы
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.50/18: Рейтинг темы: голосов - 18, средняя оценка - 4.50
0 / 0 / 0
Регистрация: 11.01.2025
Сообщений: 4

За один ход увеличить или уменьшить любой элемент массива на 1, всего таких операций можно сделать не больше K

11.01.2025, 17:09. Показов 7031. Ответов 77
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Дан список A из N чисел, а также число K. Можно за один ход увеличить или уменьшить любой элемент массива на 1, всего таких операций можно сделать не больше K раз.
Какая макс. длина может быть у какого-то подотрезка, в которым все элементы одинаковые?

В первой строке два числа - N и K. Во второй строке N чисел, i-тый элемент равен A[i].

Ограничения:
1 ≤ N ≤ 100 000
0 ≤ K ≤ 1 000 000 000
0 ≤ A[i] ≤ 100 000 000

Ввод:
11 7
3 5 8 9 2 7 6 5 3 9 7

Вывод:
4

Объяснение:
Можно выбрать отрезок 2-7-6-5. Выполним операцию 4 раза на первом элементе, тогда получаем 6-7-6-5. Выполним операцию 1 раз на втором элементе, итого 5 операции, получаем 6-6-6-5. Выполним операцию на последнем элементе, итого 6 операции, получаем 6-6-6-6. Все элементы одинаковы, значит размер отрезка (4) подходит. Можно показать, что больше такого отрезка, с длиной больше 4, нет.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
11.01.2025, 17:09
Ответы с готовыми решениями:

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

Описать ход выполнения таких операций
С Microsoft Access вообще не знаком, но попался такое задание. Описать ход выполнения следующих операций: 1. установки цвета написания...

Как можно увеличить или уменьшить изображения в Image с помощью TrackBar-а?
Добрый ноч форум! Подскажите пожалуйсто как можно увеличить или уменшить изображения в Image с помошию TrackBar -а? Добавлено...

77
820 / 579 / 75
Регистрация: 20.09.2014
Сообщений: 3,814
15.01.2025, 19:51
Студворк — интернет-сервис помощи студентам
Igor3D, чуть попозже разъясню (динамическое программирование).

Cyborg Drone, давайте возьмём простенький пример: [8, 3, 5]. Первое приближение y0 = 7.9 (просто оттолкнулись от первого числа).

y1 = {8/(8-7.9)+3/(7.9-3)+5/(7.9-5)}/{1/(8-7.9)+1/(7.9-3)+1/(7.9-5)} = 82.33/10.55 = 7.80

Мда, не быстро идет к правильному и точному ответу median = 5.

Добавлено через 24 минуты
Динамическое программирование это по сути математический метод индукции в программировании.

Если вы решили задачу для чисел [8, 3, 5], то возможно для чисел [8, 3, 5, 2] можно использовать предыдущий результат, немного модифицировав его. Этот метод не всегда работает (иногда приходится заново все пересчитывать с нуля, например, в NP-задачах). В нашей задаче работает.

Вот мы нашли медиану median([8, 3, 5]) = 5 и сохранили ранее отсортированный массив [3, 5, 8]. Вставляем в массив новое число 2, получаем [2, 3, 5, 8]. Вставка (не сортировка!!!) - это дешевая операция O(log N). Найти медиану после этого затребует O(1) усилий. Таким образом нахождение скользящей медианы не сложнее сортировки O(N log N).
Как и в методе индукции все начинается с единицы. Пользуемся правилом median([a]) = a. И после этого рекурсия пошла-поехала наращивать последовательность до рекордной длины. И нет тут никакой сортировки, просто вставка.

Аналогичная ситуация с отклонением от медианы (это что требуется вычислить в задаче).

Но на этом не заканчиваются вычисления. Надо перебрать в худшем случае все N чисел (пока лучшего я не придумал, но всё возможно). То есть берём первое число и наращиваем массив, пока затраты не превысят K. Так мы получим N рекордных длин, из них нужно выбрать чемпионскую. Это и будет ответ.
0
32 / 26 / 7
Регистрация: 22.02.2019
Сообщений: 111
15.01.2025, 22:00
Цитата Сообщение от avk959 Посмотреть сообщение
Динамическую медиану можно вычислять с помощью дерева порядковой статистики(кажется так оно у Кормена называлось).
А если это дерево вдобавок ещё сумеет подсчитать сумму элементов на отрезке за O(LogN), то должно получиться решение за O(NLogN).
В качестве первого приближения.
Собственно дерево:
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
unit OsTree;
{$mode objfpc}
interface
 
uses
  SysUtils;
 
type
  TOsTree = class
  private
  type
    PNode = ^TNode;
    TNode = record
      Left, Right: PNode;
      Value, Size: Int32;
      Prio: UInt32;
      Sum: Int64;
    end;
  var
    FRoot: PNode;
    class function  NextRandom: UInt32; static;
    class function  NewNode(aValue: Int32): PNode; static;
    class procedure ClearNode(aNode: PNode); static;
    class procedure Update(aNode: PNode); static;
    class function  GetNodeSize(aNode: PNode): SizeInt; static;
    class function  NodeByIndex(aRoot: PNode; aIndex: Int32): PNode; static;
    class procedure SplitNode(aKeyValue: Int32; aRoot: PNode; out L, R: PNode); static;
    class procedure SplitNodeI(aIdx: Int32; aRoot: PNode; out L, R: PNode); static;
    class function  MergeNode(L, R: PNode): PNode; static;
    class procedure AddNode(var aRoot: PNode; aNode: PNode); static;
    class function  RemoveNode(aKeyValue: Int32; var aRoot: PNode): Boolean; static;
    function  GetCount: Int32;
    procedure CheckIndexRange(aIndex: SizeInt);
    function  GetItem(aIndex: Int32): Int32;
  public
    destructor Destroy; override;
    function  IsEmpty: Boolean;
    procedure Clear;
    procedure Add(aValue: Int32);
    function  Remove(aValue: Int32): Boolean;
  { возвращает сумму элементов на отрезке [0, aIndex] }
    function  HeadSum(aIndex: Int32): Int64;
  { возвращает сумму элементов на отрезке [aIndex, Count-1] }
    function  TailSum(aIndex: Int32): Int64;
    property  Count: Int32 read GetCount;
    property  Items[aIndex: Int32]: Int32 read GetItem; default;
  end;
 
implementation
 
class function TOsTree.NextRandom: UInt32;
begin
  Result := UInt32(Random(Int64(High(UInt32)) + 1));
end;
 
class function TOsTree.NewNode(aValue: Int32): PNode;
begin
  New(Result);
  with Result^ do begin
    Left := nil;
    Right := nil;
    Value := aValue;
    Size := 1;
    Prio := NextRandom;
    Sum := aValue;
  end;
end;
 
class procedure TOsTree.ClearNode(aNode: PNode);
begin
  if aNode <> nil then begin
    ClearNode(aNode^.Left);
    ClearNode(aNode^.Right);
    Dispose(aNode);
  end;
end;
 
class procedure TOsTree.Update(aNode: PNode);
begin
  with aNode^ do begin
    Size := 1;
    Sum := aNode^.Value;
    if Left <> nil then begin
      Size += Left^.Size;
      Sum += Left^.Sum;
    end;
    if Right <> nil then begin
      Size += Right^.Size;
      Sum += Right^.Sum;
    end;
  end;
end;
 
class function TOsTree.GetNodeSize(aNode: PNode): SizeInt;
begin
  if aNode = nil then exit(0);
  Result := aNode^.Size;
end;
 
class function TOsTree.NodeByIndex(aRoot: PNode; aIndex: Int32): PNode;
var
  LSize: Int32;
begin
  while aRoot <> nil do begin
    LSize := GetNodeSize(aRoot^.Left);
    if LSize < aIndex then begin
      aRoot := aRoot^.Right;
      aIndex -= LSize + 1;
    end else
      if LSize > aIndex then
        aRoot := aRoot^.Left
      else
        exit(aRoot);
  end;
  Result := aRoot;
end;
 
class procedure TOsTree.SplitNode(aKeyValue: Int32; aRoot: PNode; out L, R: PNode);
begin
  if aRoot <> nil then begin
    if aRoot^.Value < aKeyValue then begin
      L := aRoot;
      SplitNode(aKeyValue, L^.Right, L^.Right, R);
    end else begin
      R := aRoot;
      SplitNode(aKeyValue, R^.Left, L, R^.Left);
    end;
    Update(aRoot);
    exit;
  end else begin
    L := nil;
    R := nil;
  end;
end;
 
class procedure TOsTree.SplitNodeI(aIdx: Int32; aRoot: PNode; out L, R: PNode);
var
  LIdx: Int32;
begin
  if aRoot <> nil then begin
    LIdx := GetNodeSize(aRoot^.Left);
    if LIdx < aIdx then begin
      L := aRoot;
      SplitNodeI(aIdx - LIdx - 1, L^.Right, L^.Right, R);
    end else begin
      R := aRoot;
      SplitNodeI(aIdx, R^.Left, L, R^.Left);
    end;
    Update(aRoot);
  end else begin
    L := nil;
    R := nil;
  end;
end;
 
class function TOsTree.MergeNode(L, R: PNode): PNode;
begin
  if L = nil then
    Result := R
  else
    if R = nil then
      Result := L
    else begin
      if L^.Prio > R^.Prio then begin
        L^.Right := MergeNode(L^.Right, R);
        Result := L;
      end else begin
        R^.Left := MergeNode(L, R^.Left);
        Result := R;
      end;
      Update(Result);
    end;
end;
 
class procedure TOsTree.AddNode(var aRoot: PNode; aNode: PNode);
begin
  if aRoot <> nil then begin
    if aRoot^.Prio < aNode^.Prio then begin
      SplitNode(aNode^.Value, aRoot, aNode^.Left, aNode^.Right);
      aRoot := aNode;
    end else
      if aNode^.Value < aRoot^.Value then
        AddNode(aRoot^.Left, aNode)
      else
        AddNode(aRoot^.Right, aNode);
    Update(aRoot);
  end else
    aRoot := aNode;
end;
 
class function TOsTree.RemoveNode(aKeyValue: Int32; var aRoot: PNode): Boolean;
var
  Node: PNode;
begin
  if aRoot = nil then exit(False);
  if aKeyValue < aRoot^.Value then begin
    Result := RemoveNode(aKeyValue, aRoot^.Left);
    if Result then Update(aRoot);
  end else
    if aRoot^.Value < aKeyValue then begin
      Result := RemoveNode(aKeyValue, aRoot^.Right);
      if Result then Update(aRoot);
    end else begin
      Node := aRoot;
      aRoot := MergeNode(aRoot^.Left, aRoot^.Right);
      Dispose(Node);
      Result := True;
    end;
end;
 
function TOsTree.GetCount: Int32;
begin
  Result := GetNodeSize(FRoot);
end;
 
procedure TOsTree.CheckIndexRange(aIndex: SizeInt);
begin
  if UInt32(aIndex) >= UInt32(Count) then
    raise EArgumentOutOfRangeException.CreateFmt('Index out of bounds(%d)', [aIndex]);
end;
 
function TOsTree.GetItem(aIndex: Int32): Int32;
begin
  CheckIndexRange(aIndex);
  Result := NodeByIndex(FRoot, aIndex)^.Value;
end;
 
destructor TOsTree.Destroy;
begin
  Clear;
  inherited;
end;
 
function TOsTree.IsEmpty: Boolean;
begin
  Result := FRoot = nil;
end;
 
procedure TOsTree.Clear;
begin
  ClearNode(FRoot);
  FRoot := nil;
end;
 
procedure TOsTree.Add(aValue: Int32);
var
  p: PNode;
begin
  p := NewNode(aValue);
  if FRoot <> nil then
    AddNode(FRoot, p)
  else
    FRoot := p;
end;
 
function TOsTree.Remove(aValue: Int32): Boolean;
begin
  if FRoot = nil then exit(False);
  Result := RemoveNode(aValue, FRoot);
end;
 
function TOsTree.HeadSum(aIndex: Int32): Int64;
var
  pL, pR: PNode;
begin
  CheckIndexRange(aIndex);
  if aIndex < Pred(FRoot^.Size) then begin
    SplitNodeI(aIndex + 1, FRoot, pL, pR);
    if pL <> nil then
      Result := pL^.Sum
    else
      Result := 0;
    FRoot := MergeNode(pL, pR);
  end else
    Result := FRoot^.Sum;
end;
 
function TOsTree.TailSum(aIndex: Int32): Int64;
var
  pL, pR: PNode;
begin
  CheckIndexRange(aIndex);
  if aIndex > 0 then begin
    SplitNodeI(aIndex, FRoot, pL, pR);
    if pR <> nil then
      Result := pR^.Sum
    else
      Result := 0;
    FRoot := MergeNode(pL, pR);
  end else
    Result := FRoot^.Sum;
end;
 
end.
И его использование:
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
program test;
{$mode objfpc}
uses
  SysUtils, OsTree;
 
var
  N: Int32 = 0;
  K: Int32 = 0;
  A: array of Int32 = nil;
 
procedure ReadInput;
var
  I: Int32;
begin
  Read(N);
  ReadLn(K);
  SetLength(A, N);
  for I := 0 to High(A) do
    Read(A[I]);
end;
 
function GetMoveCount(aTree: TOsTree): Int64;
var
  Size, Mid: Int32;
begin
  if aTree.IsEmpty then exit(0);
  Size := aTree.Count;
  Mid := Size div 2 - Ord(not Odd(Size));
  if Size > 1 then
    if Odd(Size) then
      Result := aTree[Mid] + aTree.TailSum(Mid + 1) - aTree.HeadSum(Mid)
    else
      Result := aTree.TailSum(Mid + 1) - aTree.HeadSum(Mid)
  else
    Result := aTree[Mid];
end;
 
var
  MaxLen: Int32 = 1;
  LeftIdx: Int32 = 0;
  RightIdx: Int32 = 0;
 
procedure TestMaxLen(L, R: Int32);
begin
  if Succ(R - L) <= MaxLen then exit;
  MaxLen := Succ(R - L);
  LeftIdx := L;
  RightIdx := R;
end;
 
procedure SearchFor;
var
  Tree: TOsTree;
  MoveCount: Int64;
  L, R: Int32;
begin
  L := 0;
  R := -1;
  Tree := TOsTree.Create;
  try
    while R < N - 1 do begin
      Inc(R);
      Tree.Add(A[R]);
      if GetMoveCount(Tree) <= K then
        TestMaxLen(L, R)
      else begin
        repeat
          Tree.Remove(A[L]);
          Inc(L);
          MoveCount := GetMoveCount(Tree);
        until (MoveCount <= K) or (L = R) or (N - L < MaxLen);
        if MoveCount <= K then
          TestMaxLen(L, R);
      end;
    end;
  finally
    Tree.Free;
  end;
end;
 
begin
  ReadInput;
  SearchFor;
  WriteLn('Length = ', MaxLen, ', starts at ', LeftIdx, ', ends at ', RightIdx);
end.
Как-то так пока.
0
Модератор
10465 / 5761 / 3410
Регистрация: 17.08.2012
Сообщений: 17,518
16.01.2025, 01:52
Цитата Сообщение от Mikhaylo Посмотреть сообщение
Медиана - это средний элемент отсортированного массива.
Да, так и есть... Что-то меня не туда понесло. При любом сдвиге от среднего элемента сумма расстояний никак не уменьшится.
0
32 / 26 / 7
Регистрация: 22.02.2019
Сообщений: 111
16.01.2025, 10:09
Хм, уже увидел ошибку, в программе test в строке 35 должно быть
Pascal
1
  Result := 0;
0
Модератор
Эксперт функциональных языков программирования
3140 / 2288 / 469
Регистрация: 26.03.2015
Сообщений: 8,898
16.01.2025, 11:05
Для текущего окна храним:
- координаты (границы)
- длину
- медианы (отрезок)
- количество шагов

В цикле выполняем два действия:
1. Расширяем окно вправо, пока количество шагов <= K (запоминаем лучшую длину)
2. Сужаем окно слева, пока количество шагов > K

3 5 8 9 2 7 6 5 3 9 7

Для наглядности окно буду писать в виде массива, а не границ (в коде будет два индекса).

Шаг 1. Инициализация.
([3], 1, [3..3], 0) окно [3], длина 1, медианы [3..3], количество шагов 0
Лучшая длина 1.

Шаг 2. Расширение
([3, 5], 2, ?, ?)
Так как 3 <= 3 < 5 и 2 чётное, медианы - подотрезок отрезка [3..5]. Количество шагов 2 (вычисляем для медианы 3) = 0 + (5-3).
Правую границу (5) находим методом деления пополам.
([3, 5], 2, [3..5], 2)
Лучшая длина 2.

Шаг 3. Расширение
([3, 5, 8], 3, ?, ?)
Так как 3 <= 5 < 8 и 3 нечётное, медианы - отрезок [5..5]. Количество шагов 5 (вычисляем для медианы 5) = 2 + (8-5).
([3, 5, 8], 3, [5..5], 5)
Лучшая длина 3.

Шаг 4. Расширение
([3, 5, 8, 9], 4, ?, ?)
Так как 5 <= 5 < 9 и 5 чётное, медианы - подотрезок отрезка [5..9]. Количество шагов 9 (вычисляем для медианы 5) = 5 + (9-5).
Правую границу (8) находим методом деления пополам.
([3, 5, 8, 9], 4, [5..8], 9)
Лучшая длина 3.

Шаг 5. Сужение
([5, 8, 9], 3, ?, ?)
Так как 3 < 5 <= 8 и 3 нечётное, медианы - отрезок [8..8]. Количество шагов 4 (вычисляем для медианы 8) = 9 - (8-3).
([5, 8, 9], 5, [8..8], 4)
Лучшая длина 3.

Шаг 6. Расширение
([5, 8, 9, 2], 4, ?, ?)
Так как 2 < 8 <= 8 и 4 чётное, медианы - подотрезок отрезка [2..8]. Количество шагов 10 (вычисляем для медианы 8) = 4 + (8-2).
Левую границу (5) находим методом деления пополам.
([5, 8, 9, 2], 4, [5..8], 10)
Лучшая длина 3.

И так далее.
0
1977 / 833 / 115
Регистрация: 01.10.2012
Сообщений: 5,114
Записей в блоге: 2
16.01.2025, 13:45
Цитата Сообщение от Shamil1 Посмотреть сообщение
Для текущего окна храним:
Интуитивно чувствуется что правильная идея. Но каким образом вычисляются медианы на каждом шаге?
0
Модератор
Эксперт функциональных языков программирования
3140 / 2288 / 469
Регистрация: 26.03.2015
Сообщений: 8,898
16.01.2025, 18:11
Цитата Сообщение от Igor3D Посмотреть сообщение
каким образом вычисляются медианы на каждом шаге?
Для чётной длины медиана -диапазон чисел.
Для нечётной длины медиана - одно число.


При расширении окна

Для нечётной длины медиана:
Если добавляемое число N больше/равно верхней границы H предыдущей медианы, то новая медиана [H..H]
Если добавляемое число N меньше/равно нижней границы L предыдущей медианы, то новая медиана [L..L]
Иначе новая медиана [N..N]

Для чётной длины медиана:
Если добавляемое число N больше предыдущей медианы M, то новая медиана [M..X], где X находим методом деления пополам отрезка [M..N] Нам нужно найти такую точку X, что F(X) == F(M), а F(X+1) > F(M)
Если добавляемое число N меньше предыдущей медианы M, то новая медиана [X..M], где X находим методом деления пополам отрезка [N..M]. Нам нужно найти такую точку X, что F(X) == F(M), а F(X-1) > F(M)


При сужении окна чуть сложнее, но тоже понятно, как сделать.

Добавлено через 7 минут
Возможно, для определения X проще будет пройтись по всем элементам окна и найти минимальный больше предыдущей медианы (в первом случае) или максимальный меньше предыдущей медианы (во втором случае). Поиск за линейное время, но ширина окна может быть сильно меньше диапазона медиан.

Добавлено через 1 час 24 минуты
Как-то так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
void Main()
{
    var arr = "3 5 8 9 2 7 6 5 3 9 7".Split(' ').Select(x => int.Parse(x)).ToArray();
    int k = 7;
 
    var solver = new Solver(arr, k);
    var res = solver.Solve();
    Console.WriteLine($"Result = {res}");
}
 
class Solver
{
    int k;
    int[] numbers;
    int maxWidth = 1;
    
    public Solver(int[] arr, int k)
    {
        numbers = arr;
        this.k = k;
    }
    
    public int Solve()
    {
        var w = new Window
        {
            Bounds = (0, 0),
            Medians = (numbers[0], numbers[0]),
            StepCount = 0
        };
        DoStep(w);
        return maxWidth;
    }
 
    void DoStep(Window w)
    {
        if (w.StepCount > k)
        {
            var n = numbers[w.Bounds.Low];
            w.Bounds = (w.Bounds.Low + 1, w.Bounds.High);
            Contraction(w, n);
            DoStep(w);
            return;
        }
 
        if (w.Width > maxWidth)
        {
            maxWidth = w.Width;
        }
        
        if (w.Bounds.High + 1 >= numbers.Length)
        {
            return;
        }
        
        {
            var n = numbers[w.Bounds.High + 1];
            w.Bounds = (w.Bounds.Low, w.Bounds.High + 1);
            Expansion(w, n);
            DoStep(w);
        }
    }
 
    void Contraction(Window w, int n)
    {
        if (w.Width % 2 == 1)
        {
            if (n >= w.Medians.High)
            {
                w.Medians = (w.Medians.Low, w.Medians.Low);
                w.StepCount = w.StepCount - (n - w.Medians.Low);
            }
            else if (n <= w.Medians.Low)
            {
                w.Medians = (w.Medians.High, w.Medians.High);
                w.StepCount = w.StepCount - (w.Medians.High - n);
            }
            else
            {
                throw new InvalidProgramException("not possible");
            }
        }
        else
        {
            var mOld = w.Medians.High; // w.Medians.High == w.Medians.Low
            if (n > mOld)
            {
                var low = GetNextLow(w.Bounds, mOld);
                w.Medians = (low, mOld);
                w.StepCount = w.StepCount + (mOld - n);
            }
            else if (n < mOld)
            {
                var high = GetNextHigh(w.Bounds, mOld);
                w.Medians = (mOld, high);
                w.StepCount = w.StepCount + (n - mOld);
            }
            else
            {
                var low = GetNextLow(w.Bounds, mOld);
                var high = GetNextHigh(w.Bounds, mOld);
                w.Medians = (mOld, high);
                //w.StepCount = w.StepCount;
            }
        }
    }
 
    void Expansion(Window w, int n)
    {
        if (w.Width % 2 == 1)
        {
            if (n >= w.Medians.High)
            {
                w.Medians = (w.Medians.High, w.Medians.High);
                w.StepCount = w.StepCount + (n - w.Medians.High);
            }
            else if (n <= w.Medians.Low)
            {
                w.Medians = (w.Medians.Low, w.Medians.Low);
                w.StepCount = w.StepCount + (w.Medians.Low - n);
            }
            else
            {
                w.Medians = (n, n);
                //w.StepCount = w.StepCount;
            }
        }
        else
        {
            var mOld = w.Medians.High; // w.Medians.High == w.Medians.Low
            if (n > mOld)
            {
                var high = GetNextHigh(w.Bounds, mOld);
                w.Medians = (mOld, high);
                w.StepCount = w.StepCount + (n - mOld);
            }
            else if (n < mOld)
            {
                var low = GetNextLow(w.Bounds, mOld);
                w.Medians = (low, mOld);
                w.StepCount = w.StepCount + (mOld - n);
            }
            else
            {
                w.Medians = (n, n);
                //w.StepCount = w.StepCount;
            }
 
        }
    }
 
    int GetNextLow((int Low, int High) bounds, int mOld)
    {
        var low = int.MinValue;
        for (int i = bounds.Low; i <= bounds.High; i++)
        {
            var n1 = numbers[i];
            if (n1 < mOld && n1 > low) low = n1;
        }
        return low;
    }
    
    int GetNextHigh((int Low, int High) bounds, int mOld)
    {
        var high = int.MaxValue;
        for (int i = bounds.Low; i <= bounds.High; i++)
        {
            var n1 = numbers[i];
            if (n1 > mOld && n1 < high) high = n1;
        }
        return high;
    }
 
}
 
class Window
{
    public (int Low, int High) Bounds { get; set; }
    public int Width => Bounds.High - Bounds.Low + 1;
    public (int Low, int High) Medians { get; set; }
    public int StepCount { get; set; }
}
0
820 / 579 / 75
Регистрация: 20.09.2014
Сообщений: 3,814
16.01.2025, 19:08
Shamil1, наоборот вместо диапазона медиан нужно взять одну любую (потому что без разницы). Берите первую из медиан для определенности.

Эта часть алгоритма уже понятна давно. Гораздо интереснее, как сократить перебор на самом верхнем уровне циклов.

Я предлагал наращивать подпоследовательность чисел слева и справа, может быть это и не надо. Допустим мы начали с некоторого числа, росли вправо и упёрлись в потолок роста. Есть смысл рассмотреть обмен крайнего левого числа на два крайних правых числа. Таким образом подпоследовательность явно более чемпионская, а пересчёт дешёвый. Подпоследовательность может продолжить увеличиваться и ползти вправо. Если настал окончательный тупик, то запоминаем текущую подпоследовательность и начинаем новую подпоследовательность с третьего числа предыдущей подпоследовательности.
0
32 / 26 / 7
Регистрация: 22.02.2019
Сообщений: 111
16.01.2025, 19:22
Цитата Сообщение от Igor3D Посмотреть сообщение
Интуитивно чувствуется что правильная идея.
Собственно, программа test из поста #22 именно это и делает.

Самый существенный её недостаток обусловлен использованием BST для вычисления медианы, большой массив вида [42,42,42,42,42...] для него очень неудобный набор.

Можно для поддержки динамической медианы попробовать использовать две приоритетные очереди.
0
820 / 579 / 75
Регистрация: 20.09.2014
Сообщений: 3,814
16.01.2025, 19:39
Пример: 3 5 8 9 2 7 6 5 3 9 7
K=7

1.1 median([3]) = 3, затраты 0. Одно число можно не брать в рассмотрение, переходим сразу к двум:
1.2 median([3, 5]) = 3, затраты 2
1.3 median([3, 5, 8]) = 5, затраты 5
1.4 median([3, 5, 8, 9]) = 5, затраты 9, выше потолка! Пробуем размен (заменяем 3 на 9 и 2):
1.5 median([5, 8, 9, 2]) = 5, затраты 10, выше потолка!

2.1 median([8, 9]) = 8, затраты 1
2.2 median([8, 9, 2]) = 8, затраты 7, потолок! Размен 8 на 7 и 6:
2.3 median([9, 2, 7, 6]) = 6, затраты 8, выше потолка!

3.1 median([2, 7]) = 2, затраты 5
3.2 median([2, 7, 6]) = 6, затраты 5
3.2 median([2, 7, 6, 5]) = 5, затраты 6
3.3 median([2, 7, 6, 5, 3]) = 5, затраты 8, выше потолка! Размен 2 на 3 и 9:
3.4 median([7, 6, 5, 3, 9]) = 6, затраты 8, выше потолка!

4.1 median([6, 5]) = 5, затраты 1
4.2 median([6, 5, 3]) = 5, затраты 3
4.3 median([6, 5, 3, 9]) = 5, затраты 7, потолок! Размен не получается, в последовательности осталось только одно число справа.

Хотя ни одного сдвига вправо не вышло, перебор сократился более чем вдвое.
0
Модератор
Эксперт функциональных языков программирования
3140 / 2288 / 469
Регистрация: 26.03.2015
Сообщений: 8,898
16.01.2025, 20:14
Цитата Сообщение от Mikhaylo Посмотреть сообщение
наоборот вместо диапазона медиан нужно взять одну любую (потому что без разницы).
Диапазон нужен для того, чтобы быстро пересчитывать для изменяющегося окна.

Цитата Сообщение от Mikhaylo Посмотреть сообщение
Допустим мы начали с некоторого числа, росли вправо и упёрлись в потолок роста. Есть смысл рассмотреть обмен крайнего левого числа на два крайних правых числа.
Нет смысла. Лучше уменьшить слева до "приемлемого" размера, а затем опять начать наращивать вправо.

Добавлено через 2 минуты
Обнаружил ошибку в вычислении второй границы диапазона медиан (не учитывается, что может быть несколько одинаковых чисел), которую легко исправить.

Добавлено через 13 минут
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    int GetNextLow((int Low, int High) bounds, int mOld)
    {
        var low = int.MinValue;
        var flag = false;
        for (int i = bounds.Low; i <= bounds.High; i++)
        {
            var n1 = numbers[i];
            if (flag && n1 == mOld) return mOld;
            if (n1 == mOld) flag = true;
            if (n1 < mOld && n1 > low) low = n1;
        }
        return low;
    }
 
    int GetNextHigh((int Low, int High) bounds, int mOld)
    {
        var high = int.MaxValue;
        var flag = false;
        for (int i = bounds.Low; i <= bounds.High; i++)
        {
            var n1 = numbers[i];
            if (flag && n1 == mOld) return mOld;
            if (n1 == mOld) flag = true;
            if (n1 > mOld && n1 < high) high = n1;
        }
        return high;
    }
0
820 / 579 / 75
Регистрация: 20.09.2014
Сообщений: 3,814
16.01.2025, 21:06
Цитата Сообщение от Shamil1 Посмотреть сообщение
Нет смысла. Лучше уменьшить слева до "приемлемого" размера, а затем опять начать наращивать вправо.
Точно, допустимый вариант. Две операции: а. наращивание справа (знак "+") и б. сокращение слева + наращивание справа (знак "-").

Пример: 3 5 8 9 2 7 6 5 3 9 7
K=7

1+ median([3, 5]) = 3, затраты 2
2+ median([3, 5, 8]) = 5, затраты 5
3+ median([3, 5, 8, 9]) = 5, затраты 9, выше потолка!
4- median([5, 8, 9]) = 8, затраты 4
5+ median([5, 8, 9, 2]) = 5, затраты 10, выше потолка!
6- median([8, 9, 2]) = 8, затраты 7, потолок!
7- median([9, 2, 7]) = 7, затраты 7, потолок!
8- median([2, 7, 6]) = 6, затраты 5
9+ median([2, 7, 6, 5]) = 5, затраты 6
10+ median([2, 7, 6, 5, 3]) = 5, затраты 8, выше потолка!
11- median([7, 6, 5, 3]) = 5, затраты 5
12+ median([7, 6, 5, 3, 9]) = 6, затраты 8, выше потолка!
13- median([6, 5, 3, 9]) = 5, затраты 7, потолок!
14- median([5, 3, 9, 7]) = 5, затраты 8, выше потолка!


14 шагов вместо 16 (15) в предыдущем решении.

Добавлено через 4 минуты
Shamil1, 14 шагов - безо всякой белиберды в записях типа диапазонов медиан. Впрочем, как я уже писал, пересчёт затрат также поддаётся рекурсии (динамическому программированию).

Добавлено через 6 минут
Успешная подпоследовательность - это такая, затраты которой не превышают K. Успешные подпоследовательности запоминаем.
1. Если предыдущая подпоследовательность была успешной, но есть ещё ресурс по затратам, то наращиваем справа.
2. Если предыдущая подпоследовательность не была успешной или была успешной, но затраты были равны ровно K (нет ресурса роста), то сдвигаем последнюю успешную подпоследовательность вправо.
0
1977 / 833 / 115
Регистрация: 01.10.2012
Сообщений: 5,114
Записей в блоге: 2
16.01.2025, 23:41
Цитата Сообщение от Shamil1 Посмотреть сообщение
Для чётной длины медиана..
Для нечётной длины медиана..
Эти и дальнейшие утверждения неочевидны. Напр откуда дальше берется деление отрезка пополам?

Чисто технически проблем нет. Это не такая уж редкая ситуация когда с данными надо работать с сортировкой и без. Загоняем индексы в ассоциативный контейнер, напр std::map, где сравниваем по 2 ключам (первый значение, второй индекс). Плюс храним итераторы на мапу для линейного массива. Так несложно прыгать между 2 контейнерами

Цитата Сообщение от Shamil1 Посмотреть сообщение
При сужении окна чуть сложнее, но тоже понятно, как сделать.
Да как-то не очень понятно В обильной логике легко ошибиться
0
Модератор
Эксперт функциональных языков программирования
3140 / 2288 / 469
Регистрация: 26.03.2015
Сообщений: 8,898
17.01.2025, 01:03
Цитата Сообщение от Igor3D Посмотреть сообщение
Да как-то не очень понятно
В моём сообщении есть код. И он довольно простой. Одна функция для расширения, другая - для сужения.

Цитата Сообщение от Igor3D Посмотреть сообщение
Эти и дальнейшие утверждения неочевидны.
Представьте отсортированный массив.
Если его длина нечётная, то существует один средний элемент M. Это медиана.
Если его длина чётная, то существует два средних элемента (L, H). Все числа отрезка [L..H] являются медианами.

Цитата Сообщение от Igor3D Посмотреть сообщение
Напр откуда дальше берется деление отрезка пополам?
В приведённой реализации я решил не использовать деление пополам.
В первоначально описанном варианте деление пополам - это поиск заданного значения в отсортированном массиве. Количество шагов принимает минимальное значение для медиан и монотонно возрастает (неубывающая последовательность) при удалении от неё. Получается как бы отсортированный массив значений количества шагов, где индексом является число, расстояние до которого мы считаем.

Добавлено через 3 минуты
Цитата Сообщение от Mikhaylo Посмотреть сообщение
затраты были равны ровно K (нет ресурса роста)
Ресурс роста есть даже в этом случае.

Цитата Сообщение от Mikhaylo Посмотреть сообщение
сдвигаем последнюю успешную подпоследовательность вправо.
Можно и так. Но вряд ли сдвиг будет заметно проще пары сужение-расширение.
0
820 / 579 / 75
Регистрация: 20.09.2014
Сообщений: 3,814
17.01.2025, 02:43
Цитата Сообщение от Shamil1 Посмотреть сообщение
Ресурс роста есть даже в этом случае.
Точно. Возможные редкие случаи. Но это важно.

Цитата Сообщение от Shamil1 Посмотреть сообщение
Можно и так. Но вряд ли сдвиг будет заметно проще пары сужение-расширение.
Сдвиг = сужение и расширение одновременно (в пределах одной итерации). "Расширить" мы уже написали такую функцию, осталось добавить "сузить".
0
32 / 26 / 7
Регистрация: 22.02.2019
Сообщений: 111
17.01.2025, 09:40
С двумя приоритетными очередями.
Вся возня с очередями в отдельном модуле:
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
unit MvCtr;
{$mode delphi}
interface
 
uses
  SysUtils, LgUtils, LgPriorityQueue;
 
type
  THandle = LgPriorityQueue.THandle;
  TIndexedInt = record
    Value, Index: Int32;
    constructor Make(v, i: Int32);
  end;
 
  TIdxIntCmp = record
    class function Less(const L, R: TIndexedInt): Boolean; static;
  end;
 
  TIdxIntCmpInv = record
    class function Less(const L, R: TIndexedInt): Boolean; static;
  end;
 
  TQueue = class
  private
    FQueue: IGPriorityQueue<TIndexedInt>;
    FMap: array of THandle;
    FSum: Int64;
    function GetCount: Int32;
  public
    constructor Create(aSize: Int32; aQueue: IGPriorityQueue<TIndexedInt>);
    destructor Destroy; override;
    procedure Push(const aEl: TIndexedInt);
    function  Remove(aIndex: Int32): Boolean;
    function  Contains(aIndex: Int32): Boolean;
    function  TryPeek(out aValue: Int32): Boolean;
    function  Pop: TIndexedInt;
    property  Count: Int32 read GetCount;
    property  Sum: Int64 read FSum;
  end;
 
  TMvCounter = class
  private
    FLoHalf,
    FHiHalf: TQueue;
    FMedian,
    FSize,
    FCount: Int32;
    procedure DoAdd(aValue, aIndex: Int32);
    procedure Changed;
  public
    constructor Create(aSize: Int32);
    destructor Destroy; override;
    procedure Add(aValue, aIndex: Int32);
    function  Remove(aIndex: Int32): Boolean;
    function  GetMoveCount: Int64;
  end;
 
implementation
{$coperators on}
constructor TIndexedInt.Make(v, i: Int32);
begin
  Value := v;
  Index := i;
end;
 
class function TIdxIntCmp.Less(const L, R: TIndexedInt): Boolean;
begin
  Result := L.Value < R.Value;
end;
 
class function TIdxIntCmpInv.Less(const L, R: TIndexedInt): Boolean;
begin
  Result := R.Value < L.Value;
end;
 
function TQueue.GetCount: Int32;
begin
  Result := FQueue.Count;
end;
 
constructor TQueue.Create(aSize: Int32; aQueue: IGPriorityQueue<TIndexedInt>);
begin
  SetLength(FMap, aSize);
  FQueue := aQueue;
end;
 
destructor TQueue.Destroy;
begin
  FQueue._GetRef.Free;
  inherited;
end;
 
procedure TQueue.Push(const aEl: TIndexedInt);
begin
  FMap[aEl.Index] := FQueue.Insert(aEl);
  FSum += aEl.Value;
end;
 
function TQueue.Remove(aIndex: Int32): Boolean;
begin
  if FMap[aIndex] = 0 then exit(False);
  FSum -= FQueue.Remove(FMap[aIndex]).Value;
  FMap[aIndex] := 0;
  Result := True;
end;
 
function TQueue.Contains(aIndex: Int32): Boolean;
begin
  Result := FMap[aIndex] <> 0;
end;
 
function TQueue.TryPeek(out aValue: Int32): Boolean;
var
  v: TIndexedInt;
begin
  Result := FQueue.TryPeek(v);
  if Result then aValue := v.Value;
end;
 
function TQueue.Pop: TIndexedInt;
begin
  Result := FQueue.Dequeue;
  FSum -= Result.Value;
  FMap[Result.Index] := 0;
end;
 
procedure TMvCounter.DoAdd(aValue, aIndex: Int32);
begin
  Inc(FCount);
  if FCount = 1 then
    FLoHalf.Push(TIndexedInt.Make(aValue, aIndex))
  else begin
    if aValue < FMedian then
      FLoHalf.Push(TIndexedInt.Make(aValue, aIndex))
    else
      FHiHalf.Push(TIndexedInt.Make(aValue, aIndex));
    Changed;
  end;
end;
 
procedure TMvCounter.Changed;
begin
  if Odd(FCount) then
    if FLoHalf.Count < FHiHalf.Count then
      FLoHalf.Push(FHiHalf.Pop) else
  else
    if FLoHalf.Count < FHiHalf.Count then
      FLoHalf.Push(FHiHalf.Pop)
    else
      if FLoHalf.Count > FHiHalf.Count then
        FHiHalf.Push(FLoHalf.Pop);
  FLoHalf.TryPeek(FMedian);
end;
 
constructor TMvCounter.Create(aSize: Int32);
begin
  if aSize > 0 then FSize := aSize;
  FLoHalf := TQueue.Create(FSize, TGBasePairingHeap<TIndexedInt, TIdxIntCmp>.Create);
  FHiHalf := TQueue.Create(FSize, TGBasePairingHeap<TIndexedInt, TIdxIntCmpInv>.Create);
end;
 
destructor TMvCounter.Destroy;
begin
  FLoHalf.Free;
  FHiHalf.Free;
  inherited;
end;
 
procedure TMvCounter.Add(aValue, aIndex: Int32);
begin
  if UInt32(aIndex) >= UInt32(FSize) then
    raise Exception.CreateFmt('Index out of bounds(%d)', [aIndex]);
  if FLoHalf.Contains(aIndex) or FHiHalf.Contains(aIndex) then
    raise Exception.Create('Index already added');
  DoAdd(aValue, aIndex);
end;
 
function TMvCounter.Remove(aIndex: Int32): Boolean;
begin
  Result := FLoHalf.Remove(aIndex) or FHiHalf.Remove(aIndex);
  if Result then begin
    Dec(FCount);
    Changed;
  end;
end;
 
function TMvCounter.GetMoveCount: Int64;
begin
  if FCount < 2 then exit(0);
  if Odd(FCount) then
    Result := FMedian + FHiHalf.Sum - FLoHalf.Sum
  else
    Result := FHiHalf.Sum - FLoHalf.Sum;
end;
 
end.
Собственно программа:
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
{$mode objfpc}
uses
  SysUtils, MvCtr;
 
var
  N: Int32 = 0;
  K: Int32 = 0;
  MaxLen: Int32 = 1;
  Left: Int32 = 0;
  Right: Int32 = 0;
  A: array of Int32 = nil;
 
procedure TestMaxLen(L, R: Int32);
begin
  if Succ(R - L) <= MaxLen then exit;
  MaxLen := Succ(R - L);
  Left := L;
  Right := R;
end;
 
procedure Solve;
var
  MvCount: Int64;
  L, R: Int32;
begin
  L := 0;
  R := -1;
  with TMvCounter.Create(N) do
    try
      while R < N - 1 do begin
        Inc(R);
        Add(A[R], R);
        MvCount := GetMoveCount;
        while (MvCount > K) and (L < R) and (N - L > MaxLen) do begin
          Remove(L);
          Inc(L);
          MvCount := GetMoveCount;
        end;
        if MvCount <= K then TestMaxLen(L, R)
      end;
    finally
      Free;
    end;
end;
 
var
  I: Int32;
begin
  ReadLn(N, K);
  SetLength(A, N);
  for I := 0 to High(A) do Read(A[I]);
  Solve;
  WriteLn('Length = ', MaxLen, ', starts at ', Left, ', ends at ', Right);
end.
На максимальных входных данных (N = 100000, K = 1000000000, 1<=A[i]<=50000) отрабатывает за ~40 мс, хз хорошо это или нет.
1
820 / 579 / 75
Регистрация: 20.09.2014
Сообщений: 3,814
17.01.2025, 09:52
Совет не совсем профессионального программиста остальным программистам: уровни абстракций имеет смысл плодить, только если у вас есть планы и неопределенность дальнейшего развития кода/проекта. Если ваша задача четко сформулирована, то все эти вложенные функции, объекты, конструкторы, деструкторы - это то, чем вы не воспользуетесь, только мешают.
0
1977 / 833 / 115
Регистрация: 01.10.2012
Сообщений: 5,114
Записей в блоге: 2
17.01.2025, 11:10
Цитата Сообщение от Shamil1 Посмотреть сообщение
Если его длина нечётная, то существует один средний элемент M. Это медиана.
Если его длина чётная, то существует два средних элемента (L, H). Все числа отрезка [L..H] являются медианами.
"Все числа" - но их максимум 2. Может имеется ввиду "все эл-ты с этими значениями"?
Цитата Сообщение от Shamil1 Посмотреть сообщение
Шаг 6. Расширение
([5, 8, 9, 2], 4, ?, ?)
Так как 2 < 8 <= 8 и 4 чётное, медианы - подотрезок отрезка [2..8].
Что за подотрезок и почему [2..8]?

Если же нужно просто отслеживать 1 или 2 медианы при изменении окна, то проще использовать сортированный контейнер, напр std::set или std::map (ключ = значение + индекс). При вставке/удалении известно куда "уплывет" медиана, нужно лишь подвинуть ее (итератор на нее) на 1

Добавлено через 22 минуты
Да, и если значение медианы изменилось - надо же пересчитать "число съеденных K", всех в окне ?
0
Модератор
Эксперт функциональных языков программирования
3140 / 2288 / 469
Регистрация: 26.03.2015
Сообщений: 8,898
17.01.2025, 13:06
Цитата Сообщение от Igor3D Посмотреть сообщение
"Все числа" - но их максимум 2. Может имеется ввиду "все эл-ты с этими значениями"?
Это отрезок.

Например, массив [1, 3, 7, 10]

Расстояние от 2 равно 15.
Расстояние от 3 равно 13.
Расстояние от 5 равно 13.
Расстояние от 7 равно 13.
Расстояние от 8 равно 15.

То есть, все числа от 3 до 7 являются медианами (в том смысле, который вкладывается в это слово в данной задаче).

Цитата Сообщение от Igor3D Посмотреть сообщение
проще использовать сортированный контейнер
На каждом шаге мы удаляем или добавляем элемент в/из окна. Это О(n). В то время как новое расстояние можно вычислить за O(1). Новые медианы в более, чем в половине случаев также можно вычислить за O(1).

Цитата Сообщение от Igor3D Посмотреть сообщение
Да, и если значение медианы изменилось - надо же пересчитать "число съеденных K", всех в окне ?
По коду видно, что это делается за O(1).

Цитата Сообщение от Igor3D Посмотреть сообщение
Что за подотрезок и почему [2..8]?
Новая граница медианы лежит на отрезке от 2 (новый элемент) до 8 (прежняя граница). Это такое число n, что F(n) == 10 && F(n-1) > 10. Его можно найти за логарифм (логарифм разницы двух элементов массива). Не факт, что это будет быстрее, чем перебрать все элементы окна.
0
1977 / 833 / 115
Регистрация: 01.10.2012
Сообщений: 5,114
Записей в блоге: 2
17.01.2025, 15:59
Цитата Сообщение от Shamil1 Посмотреть сообщение
То есть, все числа от 3 до 7 являются медианами
Да, и что? (в смысле зачем нам это нужно). Почему не использовать только одну (или 2) медианы "по центру"?

Цитата Сообщение от Shamil1 Посмотреть сообщение
На каждом шаге мы удаляем или добавляем элемент в/из окна. Это О(n). В то время как новое расстояние можно вычислить за O(1). Новые медианы в более, чем в половине случаев также можно вычислить за O(1).
Сортированные контейнеры что я привел - это "красно-черное дерево", скорость вставки/удаления приличная
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
17.01.2025, 15:59

Элементы массива уменьшить на 20, умножить на последний элемент и увеличить на число В
Помогите решить задачу, пожалуйста. Сама задача: &quot;Дан массив. Все его элементы уменьшить на 20, затем умножить на последний элемент,...

Элементы массива: увеличить в 2 раза, уменьшить на число А, разделить на первый элемент
Дан массив. Все его элементы: а) увеличить в 2 раза; б) уменьшить на число А; в) разделить на первый элемент.

Если последний элемент массива положителен, то все элементы увеличить на квадрат максимума всего массива
4 Задан одномерный массив F(N). Если последний элемент массива положителен, то все элементы увеличить на квадрат ...

Если последний элемент массива положителен, то все элементы увеличить на квадрат максимума всего массива
Задан одномерный массив F(N). Если последний элемент массива положителен, то все элементы увеличить на квадрат максимума всего...

Найти максимальный по значению элемент массива и увеличить его в два раза, остальные элементы уменьшить на значение минимума последней строки массива
Ввести двумерный массив A (NxM), вывести его. Найти максимальный по значению элемент массива и увеличить его в два раза. Все остальные...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
сукцессия 29. Переход от одних деревьев на другие делать более или менее вероятностным?
anaschu 12.07.2026
Насколько смена типов микоризы — исключительное событие в двухвековой сукцессии? Оценка вероятности в пространстве параметров В текущей версии модели успешно реализован ключевой механизм. . .
сукцессия 27. Думаю, как переделывать уже написанную статью с планами на сукцессию.
anaschu 12.07.2026
Анализ соответствия модели требованиям Реализованные компоненты: Механизм закисления почвы через протонную помпу Конкуренция между типами микориз pH как триггер сукцессии C/ P соотношение. . .
Сукцессия 26. Мат модель создана.
anaschu 12.07.2026
Модель смены растительных сукцессий посредством управления грибами работает внутри небольшой ячейки почвы, восстанавливающейся после пожара, где ненадолго бывшее царство хвойных снова захватили. . .
Решил проблему с ошибкой пагинации сообщений с сервера на алгоритме обхода дерева "Эстафета хвоста".
Hrethgir 12.07.2026
Проблема была в том, что удалялась именно новая кнопка, а не старая. Ни один ИИ не обнаружил это, а сам я смог только когда с работой стало попроще и когда заставил работать будущее автономное. . .
сукцессия 25. Хронология ошибок
anaschu 12.07.2026
# От 50-тонного гриба до устойчивого леса: хроника ошибок при построении модели вековой сукцессии микоризы ## О чём эта статья В процессе построения ОДУ-модели (система дифференциальных. . .
сукцессия 24. Промежуточное общее описание модели
anaschu 12.07.2026
Хендофф: модель АМ→ЭКМ сукцессии микоризы (ризосфера, 50 лет) Содержание проекта Симуляция вековой (50 лет) экологической сукцессии в почве леса Основные участники: АМ-гриб, ЭКМ-гриб,. . .
сукцессия 23. Более физиологичная физиология, более экологичная экология, более диффурные диффуры.
anaschu 12.07.2026
Что реально нашли и починили за эти 5 часов Правило Линдемана (КПД конверсии сахара в тело, kEff) — раньше 100% полученного углерода шло прямо в биомассу гриба; теперь только kEff=0. 5 (после. . .
сукцессия 22. От артефактов к физиологии: калибровка агентной модели грибной сукцессии для воспроизведения сезонной динамики и pH-плато
anaschu 11.07.2026
Аннотация В данной работе представлена калибровка агентной модели динамики грибных сообществ (fungal-succession), направленная на устранение нефизичных артефактов (коллапс биомассы, мгновенное. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru