📜  门|门 IT 2007 |第 32 题(1)

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

门|门 IT 2007 |第 32 题

这道题是门|门 IT 2007比赛中的第32题。该题涉及到计算机程序设计的知识,需要进行编程计算。详细内容如下:

题目描述

给定一个数组 $a$,数组的元素个数为 $n$。我们定义一个子数组 $a[i:j]$ 的价值为 $\sum\limits_{k=i}^{j}a[k]\times(k-i+1)$。要求计算 $a$ 的所有子数组的价值中的最大值。

输入格式
  • 第一行为一个整数 $n \ (1 \leq n \leq 10^5)$,表示数组 $a$ 中元素的个数。

  • 第二行为一个由空格隔开的 $n$ 个整数 $a_1,a_2,...,a_n$ $(1\leq a_i\leq10^6)$,表示数组 $a$ 的元素。

输出格式
  • 一个整数,表示数组 $a$ 的所有子数组中价值最大的价值。
样例
  • 输入
5
1 2 3 4 5
  • 输出
35
题解

题目要求的是数组所有子数组的最大价值,我们可以考虑枚举所有子数组,分析子数组的价值与子数组长度、首位下标、元素值之间的关系。

我们可以发现,对于一个子数组 $a[i:j]$,其价值可以表示为:

$$\begin{aligned}a[i:j]&=\sum\limits_{k=i}^{j}a[k]\times(k-i+1)\a[i:j]&=\sum\limits_{k=i}^{j}a[k] \times k - \sum\limits_{k=i}^{j}a[k] \times i + j \times \sum\limits_{k=i}^{j}a[k]\end{aligned}$$

上述式子可以用前缀和数组 $sum$ 的形式表示为:

$$a[i:j]=sum_j - sum_{i-1} - (i-1) \times (sum_j - sum_{i-1}) + j \times (sum_j - sum_{i-1})$$

我们发现,对于一个固定的 $j$,子数组的价值只与 $i$ 有关。因此我们可以通过维护两个数组 $sum$ 和 $pre$,其中 $sum_i$ 表示 $\sum\limits_{j=1}^{i}a[j]$,$pre_i$ 表示 $sum_i - (i-1)\times a_1$,然后枚举 $j$,根据上述公式进行计算,找到子数组最大价值即可。

时间复杂度 $\mathcal{O}(n)$。

代码实现
def find_max_value(n, a):
    sum_ = [0] * (n + 1)
    for i in range(1, n + 1):
        sum_[i] = sum_[i - 1] + a[i - 1]
    pre = [0] * (n + 1)
    for i in range(1, n + 1):
        pre[i] = sum_[i] - (i - 1) * a[0]
    res = 0
    for j in range(1, n + 1):
        max_value = -1
        for i in range(j):
            value = (pre[j] - pre[i]) + (j - i) * (sum_[j] - sum_[i])
            max_value = max(max_value, value)
        res = max(res, max_value)
    return res
参考链接