百度笔试真题-波动贡献最大化(C++/Py/Java /Js/Go)

波动贡献最大化

百度技术岗 笔试真题 8月6号 第一题

题目内容

运维侧拿到一条长度为 nnn 的整型指标序列 v1,v2,...,vnv_1,v_2,\dots,v_nv1,v2,...,vn,需要按连续子段做汇总评估。要求子段非空、首尾相接且覆盖整条序列,并使所有子段的「波动贡献」之和尽量大。对子段 vL,vL+1,...,vRv_L,v_{L+1},\dots,v_RvL,vL+1,...,vR,其长度为

w(L,R)=R−L+1w(L,R)=R-L+1w(L,R)=R−L+1

波动贡献定义为

H(L,R)=(max⁡(vL,vL+1,...,vR)−min⁡(vL,vL+1,...,vR))×w(L,R)H(L,R)=\bigl(\max(v_L,v_{L+1},\ldots,v_R)-\min(v_L,v_{L+1},\ldots,v_R)\bigr)\times w(L,R)H(L,R)=(max(vL,vL+1,...,vR)−min(vL,vL+1,...,vR))×w(L,R)

请给出可达到的最大总和。

输入描述

首先一行:序列长度 nnn (1≤n≤3×105)(1 \le n \le 3\times 10^5)(1≤n≤3×105)。

随后一行:nnn 个整型值构成的列表 v1,v2,...,vnv_1,v_2,\dots,v_nv1,v2,...,vn (1≤vi≤109)(1 \le v_i \le 10^9)(1≤vi≤109)。

输出描述

写出一个非负整型结果,表示该序列划分下能得到的最大总价值。

样例1

输入

复制代码
3
2 5 1

输出

复制代码
12

说明

将整段 2,5,12,5,12,5,1 作为一个子段:长度为 333,最大值为 555,最小值为 111,波动贡献为 (5−1)×3=12(5-1)\times 3=12(5−1)×3=12,即为最优总价值。

样例2

输入

复制代码
4
1 5 2 4

输出

复制代码
16

说明

将整段 1,5,2,41,5,2,41,5,2,4 作为一个子段:长度为 444,最大值为 555,最小值为 111,波动贡献为 (5−1)×4=16(5-1)\times 4=16(5−1)×4=16,即为最优总价值。

题解和思路

思路

实现思路:逻辑分析

  1. 需要分析出把一个区间拆成多个区间后,波动贡献之和一定不会超过整个区间直接作为一个子段的贡献。
  2. 具体分析过程如下,整个数组v1....vn,整体波段贡献为(max(v) - min(v)) * n
  3. 假设进行拆分
    • 左半部分长度为x, 波动为r1
    • 左半部分长度为y, 波动为r2
    • 整体长度为x + y,波动为r
    • 容易分析出r >= r1 and r >= r2 => r * (x + y) >= r1x + r2y
  4. 所以只需要遍历找出输入数组最大值、最小值,然后计算整体波动贡献即可。
  5. 代码时间复杂度为O(n)

C++

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;

    ll mn = LLONG_MAX;
    ll mx = LLONG_MIN;

    for (int i = 0; i < n; i++) {
        ll x;
        cin >> x;

        mn = min(mn, x);
        mx = max(mx, x);
    }

    cout << (mx - mn) * n << '\n';

    return 0;
}

Java

java 复制代码
import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int n = Integer.parseInt(br.readLine().trim());

        long mn = Long.MAX_VALUE;
        long mx = Long.MIN_VALUE;

        String[] nums = br.readLine().trim().split(" ");

        for (int i = 0; i < n; i++) {
            long x = Long.parseLong(nums[i]);

            mn = Math.min(mn, x);
            mx = Math.max(mx, x);
        }

        System.out.println((mx - mn) * n);
    }
}

python

python 复制代码
n = int(input())

mn = float('inf')
mx = float('-inf')

nums = list(map(int, input().split()))

for x in nums:
    mn = min(mn, x)
    mx = max(mx, x)

print((mx - mn) * n)

Javascript

js 复制代码
const readline = require("readline");

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

const input = [];

rl.on("line", line => {
    input.push(line.trim());
});

rl.on("close", () => {
    let index = 0;

    const n = Number(input[index++]);

    let mn = Number.MAX_SAFE_INTEGER;
    let mx = Number.MIN_SAFE_INTEGER;

    const nums = input[index++].split(" ").map(Number);

    for (let i = 0; i < n; i++) {
        const x = nums[i];

        mn = Math.min(mn, x);
        mx = Math.max(mx, x);
    }

    console.log((mx - mn) * n);
});

Go

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	in := bufio.NewReader(os.Stdin)
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()

	var n int
	fmt.Fscan(in, &n)

	var mn int64 = 1<<63 - 1
	var mx int64 = -1 << 63

	for i := 0; i < n; i++ {
		var x int64
		fmt.Fscan(in, &x)

		if x < mn {
			mn = x
		}

		if x > mx {
			mx = x
		}
	}

	fmt.Fprintln(out, (mx-mn)*int64(n))
}