Клиппи и Мерлин грабят банк
Клиппи и Мерлин грабят банк.
Клиппи и Мерлин решили грабить банк, который представляет собой N
расположенных в ряд банковских ячеек, пронумерованных последовательно числами от 1 до N.
С помощью своего друга Ровера, который работал в банке сторожевым псом, они добыли ключи от всех ячеек, а так же узнали, как много ценностей хранится в каждой ячейке.
Чтобы не вызывать лишних подозрений, Клиппи и Мерлин решили ограбить всего две ячейки — по одной на каждого. Также, чтобы охрана банка не почуяла неладного, они решили работать далеко друг от друга — между ними должно быть не меньше K банковских ячеек.
Входные данные
В первой строке вводятся два числа — N ( 2 ≤ N ≤ 10^5) и K (0 ≤ K < N−1) соответственно. В второй строке вводятся N чисел ai(0 ≤ai≤ 10^9) — стоимости хранимых ценностей в ячейках от 1 до N соответственно.
Выходные данные
Выведите два числа в возрастающем порядке — номера ячеек, которые нужно ограбить, чтобы суммарно украсть как можно более дорогие ценности, не вызвав при этом лишних подозрений. Если вариантов несколько выберите тот, в котором меньший номер вскрываемой ячейки был как можно ближе к единице, чтобы в экстренном случае покинуть банк как можно скорее. Если и таких вариантов несколько, выберите тот, в котором и больший номер вскрываемой ячейки был как можно меньше.
Пример:
Ввод:
6 2
2 4 3 1 4 4
Вывод:
2 5
n,k=map(int,input().split())
a=list(map(int,input().split()))
ibest = 0
jbest = k + 1
j=k+1
for i in range(n):
if j==n:
break
if (a[i] + a[j] > a[ibest] + a[jbest]):
m= a[i] + a[j]
ibest=i
jbest=j
j+=1
print(str(ibest+1)+' '+str(jbest+1))
Написал этот код, тестирующая система выдаёт ошибку(проходит 7 из 17 тестов), что нужно исправить+нужно сохранить линейную сложность O(n). Ссылка на источник https://informatics.mccme.ru/mod/statements/view.php?id=13551#1
Ответы (5 шт):
Приведённый код, похоже, учитывает только пары с расстоянием точно k, а нужно не меньше k
Для этого можно заполнить вспомогательный список/массив индексом максимального элемента в правой части списка от каждого лемента до конца (с помощью прохода в обратном направления)
Потом идти с начала, обновляя индекс максимума в левой части списка. Результат есть максимум суммы правый максимум + левый максимум для индексов, разнесённых на k
Решение
def linear(cells):
max_a = 0
max_a_i = 0
max_sum = 0
# Перебираем все возможные левые ячейки - 'a'
for a_i, a in enumerate(cells[:-distance - 1]):
# Находим ближайшую правую ячейку
b_i = a_i + distance + 1
b = cells[b_i]
# Запоминаем левую ячейку с максимальным значением.
if a > max_a:
max_a = a
max_a_i = a_i
# По условию для текущей правой ячейки ('b') подойдёт любая
# левая, стоящая от неё на расстоянии больше, чем 'k'.
# Логично, что надо выбрать левую ячейку с максимальным значением.
# Таким образом, сложив правую ячейку с максимальной левой, получаем
# лучшую сумму для данной правой ячейки.
if max_a + b > max_sum:
max_sum = max_a + b
# После проверки всех ячеек, в 'answer' будут номера
# 'a' и 'b' с лучшей суммой
answer = (max_a_i, b_i)
print(answer[0] + 1, answer[1] + 1)
Тестирование
# Содержимое файлов с тестами
$ tail -n +1 -- input_*
==> input_1.txt <==
6 0
2 9 9 1 4 4
==> input_2.txt <==
6 1
5 7 6 8 0 0
==> input_3.txt <==
6 1
5 9 9 1 4 6
==> input_4.txt <==
10 1
1 1 4 1 1 1 3 1 3 1
Команда на bash для проверки тестов:
$ for f in input*; do echo "${f}"; ./source.py < "${f}"; echo; done
Output
input_1.txt
2 3
input_2.txt
2 4
input_3.txt
2 6
input_4.txt
3 7
args = [int(i) for i int(input().split()]
n, k = args[0], args[1]
a = [int(i) for i in input().split()]
ibest = 0
jbest = k+1
imax = 0
for j in range(k+1, n):
if a[j-k-1] > a[imax]:
imax = j-k-1
if (a[j] + a[imax]) > (a[jbest] + a[ibest]):
jbest = j
ibest = imax
print(ibest+1, jbest+1)
Все тесты Сириуса прошел. Если не трудно, поставьте большой палец)
Тоже проходит тесты:
N,K = map(int,input().split())
Cells = list(map(int,input().split()))
max1 = 0
max2 = 0
max_right = []
for i in range(N - 1,K, -1):
if Cells[i] > max1:
max_right.append(Cells[i])
max1 = Cells[i]
else:
max_right.append(max1)
max_right = list(reversed(max_right))
#Начальный индекс с максикальной суммой
for i in range(N - K - 1):
S = Cells[i] + max_right[i]
if S > max2:
max2 = S
index1 = i
v = []
for i in range(index1 + K + 1, N):
v.append(Cells[i])
print(index1 + 1, v.index(max_right[index1]) + index1 + K + 1 + 1)
Для линейной асимптотики нужно, чтобы мы использовали информацию о уже просмотренных элементах. Разумеется для бОльшей награды нам нужно брать максимум, который можно взять. Давайте же и будем подсчитывать максимум и для Клиппи, и для Мерлина, не забывая про расстояние К:
n,k=map(int,input().split())
a=list(map(int,input().split()))
#мы должны работать не менее К ячеек друг от друга. так как K<=N-1, понимаем, что
# оба работника уместятся.
# Алгоритм простой, буду находить локальный максимум и для Клиппи, и для Мерлина
k+=1#для того расстояния
right_i=k
left_i=0
maxi=0
for i in range(k+1,n):
if a[i-k]>a[maxi]:
maxi=i-k # ищу максимум для левого вора
# сверяю текущую пару и лучшую,
# a[i] - это правый вор,
# a[maxi] - левый вор, которого мы хотим взять
if a[i]+a[maxi]> a[left_i]+a[right_i]:
left_i=maxi
right_i=i
print(left_i+1,right_i+1)
Ваш алгоритм не сработал, так как вы не находите максимум для левого вора, который вы будете использовать для сравнения