Python

Торговля акциями. Линейные алгоритмы. Python.

Торговля акциями
В настоящее время на бирже при торговле акциями активно применяются компьютерные системы, которые упрощают и автоматизируют процесс покупки и продажи акций. Некоторые из них даже позволяют вести торговлю вообще без участия человека.

Разумеется, основным критерием, по которому такие системы оцениваются, является прибыль, которую приносит торговля с их применением. Для того, чтобы ее повысить при построении этих систем применяются различные математические методы и модели.

Основной трудностью при создании таких систем является то, что они должны некоторым образом учитывать изменение стоимости акций в будущем, а также его прогнозировать. Ваша задача несколько проще — курсы продажи и покупки акций за весь период из N дней уже известны, необходимо лишь разработать оптимальную стратегию продаж и покупок. При этом для простоты будем считать, что за эти N дней купить акции можно не более одного раза и продать акции можно также не более одного раза.

Кроме этого, будем считать, что продажа и покупка будет осуществляться только с акциями одного типа. На начало этого периода вы располагаете суммой в X рублей. Для каждого из дней известна цена ai (от ask — цена предложения), по которой можно купить одну акцию, и цена bi, по которой можно одну акцию продать. При этом в соответствии с действующими правилами торгов на бирже разрешается продавать и покупать только целое число акций (например, если у вас есть 5 рублей, а акция стоит 2 рубля, то вы можете купить не более двух акций). Требуется написать программу, которая по имеющимся данным о стоимости акций в каждый из дней, найдет оптимальную стратегию покупки и продажи акций.

Входные данные

Первая строка содержит два целых числа N и X (1 ≤ N ≤ 100 000,1 ≤ X ≤ 10^6). Вторая строка содержит N целых чисел a1, ..., aN. Третья строка содержит N целых чисел b1, ..., bN(1 ≤ bi ≤ ai ≤ 1 000).

Выходные данные

В первой строке выведите максимальную сумму, которой вы можете обладать по окончании рассматриваемого периода. Во второй строке выведите два числа — номер дня d1, в который следует купить акции, и номер дня d2, в который эти акции следует продать (должно выполняться неравенство d2 > d1). При этом подразумевается, что покупается столько акций, сколько их можно купить на X рублей, а потом они все продаются. Если в найденной вами стратегии продавать и покупать акции не требуется, то выведите во второй строке "−1 −1". Если существует несколько вариантов оптимальной стратегии, то выведите любой из них.

Примеры
Ввод
5 1000
2 3 1 4 3
1 2 1 2 3
Вывод
3000
3 5
Ввод
5 1000
10 9 8 7 6
9 8 7 6 5
Вывод
1000
-1 -1
Мой код не проходит по времени. Помогите, пожалуйста.
n, x = map(int, input().split())

a = list(map(int, input().split()))
b = list(map(int, input().split()))

top = x
top_buy = -1
top_sell = -1
m = 0

for i in range(n):
h = x // a[i]
o = x % a[i]
if top_sell < i + 1:
c = b[i:]
m = max(c)
top_sell_new = c.index(m) + i + 1
if m * h + o > top:
top = m * h + o
top_buy = i + 1
top_sell = top_sell_new
print(top)
print(top_buy, top_sell)
Вот еще вариант:
https://pastebin.com/iCRBC5RY

Задача №1253. Торговля акциями
##s1 = '5 1000'
##s2 = '10 9 8 7 6'
##s3 = '9 8 7 6 5'
##s2 = '2 3 1 4 3'
##s3 = '1 2 1 2 3'
s1 = input()
s2 = input()
s3 = input()
n, x = map(int, s1.split())
A = list(map(int, s2.split()))
B = list(map(int, s3.split()))
# Вспомогательный список
# B[i][0] - масимальная цена продажи в этот день и позже
# B[i][1] - индекс дня с максимальной ценой продажи
B[-1] = (B[-1], -1)
for i in range(2,len(B)):
~~~~if B[-i] > B[-i+1][0]:
~~~~~~~~B[-i] = (B[-i], -i)
~~~~else:
~~~~~~~~B[-i] = B[-i+1]

a_mn = A[0]# минимальная цена покупки не позже текущего дня
a_mni = 0# индекс для с минимальной ценой покупки
mx = x# максимальные деньги после покупки-продажи
mx_ij = (-1,-1)# дни покупки и продажи, нумерация с 1
for i in range(len(A)-1):# -1 потому, что покупать в последний день нельзя
~~~~if A[i] < a_mn:
~~~~~~~~a_mn = A[i]
~~~~~~~~a_mni = i
~~~~n_buy = x // a_mn# число купленных
~~~~rest = x % a_mn# сдача
~~~~x_sell = n_buy * B[i+1][0] + rest# деньги после продажи в этот день
~~~~if x_sell > mx:
~~~~~~~~mx = x_sell
~~~~~~~~mx_ij = (i+1, len(B) + B[i+1][1] +1)

print(mx)
print(*mx_ij)
Оралбаев Бахытжан
Оралбаев Бахытжан
21 729
Лучший ответ
Эдуард Лотов Спасибо Вам огромное!
n, x = map(int, input().split())
a = list(map(int, input().split()))
b = list(map(int, input().split()))

maxa,minb=max(a),min(b)
minind,maxind=b.index(minb),a.index(maxa)
kvoak=x//minb

if minind < maxind and maxa/minb > 1:
~~print ((maxa-minb)*kvoak,'\n',minind+1, maxind+1)
else: print ('-1 -1')

В ответе на первый пример, видимо, опечатка... Акции выгоднее всего продать не на 5-й день, а на 4-й, когда за них дают по 4 рубля! Покупать же их выгодно на 1-й или 3-й день по 1 рублю. Заработанная сумма правильная (4-1)*1000=3000.

Второй пример - правильный.
Yan Erlats
Yan Erlats
92 581
Роман Гордеев Неправильное решение. Задача сложнее. Возможна ситуация, что оптимальны цены покупки/продажи не равны min/max ценам.
Сценарий: сначала цена падает, потом растёт, но не доходит до начальной цены. Потом падает ещё ниже, чем при первом падении.
Ермек Мухамбетов "В ответе на первый пример, видимо, опечатка... Акции выгоднее всего продать не на 5-й день, а на 4-й, когда за них дают по 4 рубля! Покупать же их выгодно на 1-й или 3-й день по 1 рублю."

5 1000
2 3 1 4 3
1 2 1 2 3

Вы попутали строки с ценами покупки и ценами продажи. Продажа самая нижняя.

И расчет результата у Вас неправильный,
не (4-1)*1000,
а 1000//1*4 + 1000%1 = 4000
а учитывая, что сначала цены покупки, а ниже цены продажи, то
1000//1*3 + 1000%1 = 3000
Это ваша первая задача на оптимизацию кода?

Для ускорения работы нужно НЕ делать того, что делать не нужно, избегая или минимизируя повторения. В данном случае в каждом цикле вы обрезаете массив, просматриваете весь срез на предмет максимума, а потом ещё раз просматриваете до поиска индекса этого максимума.

Для начала можно не пользоваться стандартными функциями, и искать в цикле ручками без срезов и повторений поиска индекс и максимум одновременно.
Второй этап оптимизации. Как не трудно заметить, пока вы в цикле не достигнете индекса максимума, результат поиска не изменится. (вы это заметили)
Последний вариант, заранее обработать массив B, создав служебные структуры, чтобы получать ответ о максимуме и индексе для каждого i без просмотра массива, используя эти структуры.

Примерно так оптимизируется код в реальной жизни. Сначала устраняются явные косяки кода без вмешательства в алгоритм, если не повезёт, то нужно искать какую-то изюминку, ускоряя работу, и в самом последнем случае сесть и переделать весь алгоритм.
ЗЫ
Ответы не любят пробелы в начале строк, а разработчики не сделали исключение для раздела Python'а, код на нём удобнее читать на скриншоте или на специализированном сайте обмена кодами типа pastebin
Такой https://ideone.com/G8bmax код приятнее.
Yan Erlats Я быстрее написал программу из нескольких строк, чем прочел этот, бесспорно, поучительный текст... :)))

n, x = map(int, input().split())
a = list(map(int, input().split()))
b = list(map(int, input().split()))

maxa,minb=max(a),min(b)
minind,maxind=b.index(minb),a.index(maxa)
kvoak=x//minb

if minind < maxind and maxa/minb > 1:
~~print ((maxa-minb)*kvoak,'\n',minind+1, maxind+1)
else: print ('-1 -1')
Оралбаев Бахытжан "Такой https://ideone.com/G8bmax код приятнее."

Forbidden

Напомнило песенку:
" У нас есть ТАКИЕ!!! приборы.
Но мы вам о них не расскажем!" (С) Манго-Манго
Эдуард Лотов "Такой https://ideone.com/G8bmax код приятнее."
Программа выдаёт неверный ответ...
Эдуард Лотов Подсказка:
"Обратите внимание, что мы максимизируем не прибыль от покупки-продажи акции, а сумму денег на момент продажи, то есть надо учитывать и оставшиеся от покупки средства".
ясно.
JM
Joomart Miyzamov
1 794
N, money = map(int, input('Кол-во дней и началаьная сумма: ').split())
buy = list(map(int, input('Цена покупки: ').split()))
sell = list(map(int, input('Цена продажи: ').split()))
bestseller = 0
best_buy, best_sell = -2, -2
for i in range(N - 1): # по условию, акции нельзя продать в день покупки
~price = max(sell[i + 1:])
~if price - buy[i] > bestseller:
~~bestseller = price - buy[i]
~~best_buy, best_sell = i, sell.index(price)
if bestseller > 0:
~money = money // buy[best_buy] * sell[best_sell] + money % buy[best_buy]
print(money)
print(best_buy + 1, best_sell + 1)

P.S.
'~' = отступ в четыре пробела
YY
Yaguar Yaguar
363
Оралбаев Бахытжан В код не вникал, но для
=========
5 1000
5 3 7 1 4
4 2 6 1 3
1999
2 3
>>>
явно ошибка.
Так как купив в 4-й день 1000 акций по 1, можно продать их в 5-й день по 3 и иметь не 1999, а 3000.
Эдуард Лотов Спасибо, но код не проходит по времени...
Yaguar Yaguar Спасибо за замечание, исправил и доработал код:

N, money = map(int, input('Кол-во дней и начальная сумма: ').split())
buy = list(map(int, input('Цена покупки: ').split()))
sell = list(map(int, input('Цена продажи: ').split()))
bestseller = 0
best_buy, best_sell = -2, -2
for i in range(N - 1): # по условию, акции нельзя продать в день покупки
~price = max(sell[i + 1:])
~if price // buy[i] > bestseller:
~~bestseller = price // buy[i]
~~best_buy, best_sell = i, sell.index(price)
~elif price // buy[i] == bestseller and bestseller > 0:
~~if money // buy[i] > money // buy[best_buy]:
~~~best_buy, best_sell = i, sell.index(price)
if bestseller > 0:
~money = money // buy[best_buy] * sell[best_sell] + money % buy[best_buy]
print(money)
print(best_buy + 1, best_sell + 1)