牛牛与切割机
[题目链接](https://www.nowcoder.com/practice/cda06078a54142d29da7adc3b9ad5880)
思路
有一个序列 ,将其切割一刀,分成两个非空的连续子序列
和
(
),切割代价为两部分元素和的乘积。求最小切割代价。
前缀和枚举
设总和为 ,前缀和为
。在位置
处切割的代价为:
$$
只需遍历所有合法切割点 ,维护前缀和并计算代价,取最小值即可。
样例演示
输入 ,总和
:
| 切割位置 |
左部分和 |
右部分和 |
代价 |
|---|---|---|---|
| 1 | 1 | 14 | 14 |
| 2 | 3 | 12 | 36 |
| 3 | 6 | 9 | 54 |
| 4 | 10 | 5 | 50 |
最小代价为 。
复杂度分析
- 时间复杂度:
,遍历一次数组计算前缀和并求最小值。
- 空间复杂度:
,存储输入数组(也可优化到
,边读边算)。
代码
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
int main() {
int n;
cin >> n;
vector<long long> a(n);
long long total = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
total += a[i];
}
long long ans = LLONG_MAX;
long long prefix = 0;
for (int i = 0; i < n - 1; i++) {
prefix += a[i];
long long cost = prefix * (total - prefix);
if (cost < ans) ans = cost;
}
cout << ans << endl;
return 0;
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
long[] a = new long[n];
long total = 0;
for (int i = 0; i < n; i++) {
a[i] = sc.nextLong();
total += a[i];
}
long ans = Long.MAX_VALUE;
long prefix = 0;
for (int i = 0; i < n - 1; i++) {
prefix += a[i];
long cost = prefix * (total - prefix);
if (cost < ans) ans = cost;
}
System.out.println(ans);
}
}

京公网安备 11010502036488号