среда, 25 января 2017 г.

11A Электив

Задача.    На вход программы подаются результаты измерений, выполняемых прибором с интервалом 1 минуту. Все данные – целые числа (возможно, отрицательные). Требуется найти наибольшую сумму двух результатов измерений, выполненных с интервалом не менее, чем в 7 минут. В первой строке вводится одно целое положительное число – количество измерений N, которое может быть очень велико. Гарантируется, что N > 7. Каждая из следующих N строк содержит по одному целому числу – результат очередного измерения.
Решение (Поляков К.Ю.)
1)     Сначала поймем, что требуется найти. Предположим, что все результаты измерения
записаны в массив:

Нужно найти пару элементов с максимальной суммой, отстоящих друг от друга не менее, чем на K (в данной задаче K = 7) позиций в массиве, то есть разность их индексов должна быть больше или равна K. Предположим, что второй элемент в паре (стоящий ближе к концу массива) имеет индекс i. Тогда соответствующий первый элемент из той же пары нужно искать в диапазоне индексов от 1 до i-K (см. желтую зону на рисунке). 
Для элемента с индексом i наибольшую сумму даст  наибольший элемент из этого диапазона. Его можно найти эффективно в процессе ввода элементов следующим образом. Предположим, что мы уже знаем максимальный элемент (обозначим его max) в диапазоне индексов от 1 до i-K-1. При переходе к следующему значению i нам нужно найти максимум из элементов с индексами от 1 до i-K, то есть к уже рассмотренным элементам  (для которых мы знаем максимум max) добавляется один элемент Buf[i-K], выделенный голубым цветом на рисунке:
Поэтому новый максимум – это наибольшее значение из mаx и Buf[i-K].
Итак, если второй элемент в паре имеет индекс i, то в качестве значения первого элемента мы можем взять найденное выше значение max. Из всех таких пар (при всех i от K+1 до N) нужно выбрать пару с максимальной суммой (будем хранить её в переменной maxSum):
if max + Buf[i] > maxSum then
      maxSum := max + Buf[i]; 
Организуем эффективное хранение данных. Когда мы читаем из входного потока очередной элемент (в массиве он хранился в элементе с индексом i), то на этом шаге нужно добавить к элементам, среди которых ищется максимум, элемент, прочитанный на K шагов раньше, то есть, нужно хранить (в массиве) только K предыдущих элементов. Размер этого массива K не зависит от N, которое может быть очень большим. После использования значения с номером i-K для поиска максимума нужно запомнить в массиве только что прочитанное значение.
Структура данных, с помощью которой можно решить эту задачу, называется очередью. Элементы в очередь добавляются с одного конца (это будет конец массива), а извлекаются – с другого (с начала массива). После удаления первого элемента (который «включается» в поиск максимума) все элементы очереди, начиная со второго, сдвигаются на одну позицию к началу массива, а в последний (освободившийся) элемент записывается только что прочитанное значение (оно хранится в переменной elem):

Сначала нужно заполнить очередь: прочитать в неё первые K измеренных значений:
var Buf: array[1..K] of integer;
...
for i:=1 to K do
  read(Buf[i]);
Затем читаем и обрабатываем оставшиеся N-K значений:
for i:=K+1 to N do begin
  read(elem);
...
end;
На первом шаге этого цикла записываем в переменную max первый элемент очереди, а в переменную maxSum – сумму max и только что прочитанного значения elem; на остальных шагах цикла обновляем эти максимальные значения:
if i = K+1 then begin
  max := Buf[1];
  maxSum := Buf[1] + elem;
end
else begin
  if Buf[1] > max then
    max := Buf[1];
  if max+elem > maxSum then
    maxSum := max + elem;
end
После этого нужно сдвинуть все элементы очереди на одну позицию к началу (удалить уже использованный первый элемент) и добавить в конец очереди новое значение elem:
for j:=1 to K-1 do
  Buf[j] := Buf[j+1];
Buf[K] := elem;
В конце цикла нужное значение оказывается в переменной maxSum. Приведём полное правильное решение, эффективное как по времени выполнения (оно линейно зависит от N), так и по используемой памяти (не зависит от N):
const K = 7;
var i, j, N, max, maxSum, elem: integer;
    Buf: array[1..K] of integer;
begin   
  read(N);
    { заполняем очередь }
  for i:=1 to K do read(Buf[i]);
    обрабатываем оставшиеся данные }
  for i:=K+1 to N do begin
    read(elem);
    if i = K+1 then begin  { начальные значения max и maxSum }
      max := Buf[1];
      maxSum := Buf[1] + elem;
    end
    else begin { обновление max и maxSum }
      if Buf[1] > max then max := Buf[1];
      if max+elem > maxSum then
         maxSum := max + elem;
    end;     
      { обработка очереди }
    for j:=1 to K-1 do     сдвиг очереди }
      Buf[j] := Buf[j+1];
    Buf[K] := elem;        { добавить элемент в очередь } 
  end; 
  writeln(maxSum); 
end.

Комментариев нет:

Отправить комментарий