📜  门| GATE 2017 MOCK II |问题 24(1)

📅  最后修改于: 2023-12-03 15:28:36.474000             🧑  作者: Mango

门 | GATE 2017 MOCK II | 问题 24

题目描述

有一个 $n$ 个门的大厦,每个门都有一个数 $a_i$,其中 $i \in [1, n]$。你可以选择从任何门出发,但是你每次只能选择跳到比当前门数字更小的下一扇门。你可以一直跳下去,直到不能再跳为止。找出可以获得的最大积分。

例如:一个大厦有4个门,每个门数字为 [10, 5, 4, 3],你选择从第一扇门出发,跳到每个门的路径为 [10, 5, 4, 3],你可以获得的积分为 $10 * 5 * 4 * 3 = 600$。

输入格式

第一行包含一个整数 $t$,表示测试用例的数量。

每个测试案例的第一行包含一个整数 $n$,表示大厦中门的数量。

接下来一行含有 $n$ 个整数 $a_i$,其中 $i \in [1, n]$,表示每个门的数字。

输出格式

对于每个测试用例,输出一个整数,表示可以获得的最大积分。

限制条件

$1 \leq t \leq 10$

$1 \leq n \leq 10^3$

$0 \leq a_i \leq 10^5$

题解

这是一个经典的动态规划问题。对于每个门,我们需要计算当从这扇门出发时可以获得的最大积分。

我们设 $dp[i]$ 表示从第 $i$ 扇门出发可以获得的最大积分。因为我们可以从 $i$ 跳到比它更小的任何下一扇门,所以我们可以将 $dp[i]$ 定义为:

$$ dp[i] = a[i] * \max_{j= i+1}^{n} {dp[j]} $$

其中,$j$ 表示下一扇门的编号。换句话说,我们根据比当前门数字更小的下一扇门的最大积分计算当前门的最大积分。

由于我们需要找到比 $i$ 更小的下一扇门的最大积分,所以我们可以倒序迭代大厦门的数组。这样,我们可以确保在计算 $dp[i]$ 时,比 $i$ 更小的下一扇门的最大积分已经计算完毕。

我们最终的答案就是所有门中 $dp[i]$ 的最大值。

以下是代码:

def max_score(n: int, a: List[int]) -> int:
    dp = [1] * n
    
    for i in range(n - 2, -1, -1):
        for j in range(i + 1, n):
            if a[j] < a[i]:
                dp[i] = max(dp[i], a[i] * dp[j])
    
    return max(dp)

if __name__ == '__main__':
    t = int(input())
    
    for i in range(t):
        n = int(input())
        a = list(map(int, input().split()))
        print(max_score(n, a))

代码的时间复杂度是 $O(n^2)$。因为我们需要迭代数组两遍,所以即使在最坏的情况下,当 $n=10^3$ 时,代码的运行时间仍然不到一秒。