波动贡献最大化
百度技术岗 笔试真题 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,即为最优总价值。
题解和思路
思路
实现思路:逻辑分析
- 需要分析出
把一个区间拆成多个区间后,波动贡献之和一定不会超过整个区间直接作为一个子段的贡献。 - 具体分析过程如下,整个数组
v1....vn,整体波段贡献为(max(v) - min(v)) * n - 假设进行拆分
- 左半部分长度为
x, 波动为r1 - 左半部分长度为
y, 波动为r2 - 整体长度为
x + y,波动为r - 容易分析出
r >= r1 and r >= r2=>r * (x + y) >= r1x + r2y
- 左半部分长度为
- 所以只需要遍历找出输入数组最大值、最小值,然后计算整体波动贡献即可。
- 代码时间复杂度为
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))
}