您在一行中有n个商店,每个商店都有相关的金额$ c_i $。在时间1,您从商店1开始。在随后的每个时间,您可以选择访问商店i-1,停留在商店i或访问商店i + 1。无论您访问过该商店多少次,您都可以在每个时间步骤中假设自己在商店i中收集$ c_i $的钱。
给出一次$ t_j $的时间列表,找到可以在$ t_j $个时间步长内收集钱的情况下可以收集的最大金额。
我在想办法预处理数据时遇到了麻烦。我的想法是,对于每个展位,我想找到一个时间间隔,在该时间间隔内,最好直接赶到那个展位并停留在那儿,在每个时间步骤都收钱。我不确定在O(n)时间还是O(nlogn)时间有效地执行此操作的正确方法。
编辑:我目前正在为每个摊位做一个工作,我有一个随时间变化的表达式,表示如果我直接去展位并呆在那里,我可以收取的最大金额。然后每次,我都将所有这些功能发挥到最大。这需要线性时间来处理每次查询。我想要一个对数的方法。
答案 0 :(得分:0)
您直接通过前往商店i
并在给定的总时间t
停留在商店中来返回金额的收益函数是
r_i(t) = sum(j from 1 to i - 1: c_j) + c_i * (t - i + 1)
每个i
的总和可以递增计算,您会得到一个整齐的线性函数:
r_i(t) = a_i + b_i * t
带有a_i = sum as above + (1 - i) * c_i
和b_i = c_i
。
现在,对于每次t
,您要查找所有r_i(t)
中的最大值。为此,我们可以使用功能的排序。具体来说,如果函数f1
在其交点之前大于f2
,我们可以对它们进行排序,以使函数f1
早于f2
出现。然后,如果我们具有给定点t
的可用功能(在r_i
中可以到达的所有t
),我们只需要逐步执行有序序列即可。对于开始时间,第一个元素将是最佳功能。然后,我们可以使用下一个功能检查交点。如果t
在该交点之后,我们将继续执行此功能,因为这将是当前间隔的新最大值。等等。如果您按时间对查询进行排序,则可以针对每个查询以增量方式完成此操作。在执行此过程时,您还需要添加可用的新功能。使用适当的数据结构(例如,二进制搜索树),您可以在O(log n)中进行插入。
那么,我们如何比较两个函数f1(t) = a1 + t * b1
和f2(t) = a2 + t * b2
?相交点为ti = (a2 - a1) / (b1 - b2)
。如果f1
,则f2
大于b1 < b2
。
这是整体算法:
input: n stores, q queries Q
sort queries by time - O(q log q)
create empty BST
currentBestFunction = empty //pointer to element in BST
nextQuery = Q.first
sumCi = 0 //temporary variable for incremental sum
for t = 1 to maxQ
if t <= n
// we can reach a new store
a = sumCi + (1 - t) * c_t
b = c_t
sumCi += c_t
insert function (a, b) into BST - O(log n)
if currentBestFunction = empty
currentBestFunction = the inserted function
while currentBestFunction is not the last function in BST
successor = find successor function to currentBestFunction in BST
calculate intersection ti = (successor.a - currentBestFunction.a) / (currentBestFunction.b - successor.b)
if ti > t
break //we are in the interval for the current best function
else
currentBestFunction = successor
loop
if nextQuery == t
answer query by evaluating currentBestFunction at t
advance nextQuery
if no more queries then stop