NC14291 Cut

题目链接

题目

题目描述

给你一个长度为 n 的序列,你每次可以将一个序列分割成两个连续的的子序列,
分割的代价为原序列的总和。
现在允许你在初始时将序列重新排列一次。
问分割成 n 个长度为 1 的序列的最大总代价是多少?

输入描述

第一行一个数 n 表示原序列的长度;
接下来一行 n 个数 ai 表示原序列的第 i 个数。
2<=n<=100000
0<=ai<=10000

输出描述

一行一个整数表示答案。

示例1

输入

4
3 2 4 1

输出

26

说明

[3,2,4,1]重排->[1,2,3,4]->[1],[2,3,4]->[1],[2],[3,4]->[1],[2],[3],[4]。

示例2

输入

4
1 1 1 1

输出

9

题解

方法一

知识点:贪心,数学。

显然,每次把最小的取出来,大的加的机会就更多。

不妨再进一步思考,实际上从小到大取,第 i 个数会加 i 次。特别地,最后一个数只有 n1 次,因为最后一次没有取。

所以有 ans=i=1niaian

时间复杂度 O(n)

空间复杂度 O(n)

方法二

知识点:贪心,优先队列。

贪心思路还是一样的,不过这次用优先队列傻瓜式维护即可。

不过需要注意的是,为了方便我们假设一个等价情形,元素还未合并,要求每次合并两段序列,使得最后花费最多。显然是从大的先合并,答案和从小开始的分割序列等价。于是,很容易用优先队列维护。

时间复杂度 O(nlogn)

空间复杂度 O(n)

代码

方法一

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[100007];
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i];
sort(a + 1, a + 1 + n);
ll ans = -a[n];
for (int i = 1;i <= n;i++) {
ans += 1LL * i * a[i];
}
cout << ans << '\n';
return 0;
}

方法二

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
priority_queue<ll> pq;
for (int i = 0, tmp;i < n;i++) cin >> tmp, pq.push(tmp);
ll ans = 0;
for (int i = 0;i < n - 1;i++) {
ll sum = pq.top();
pq.pop();
sum += pq.top();
pq.pop();
pq.push(sum);
ans += sum;
}
cout << ans << '\n';
return 0;
}
posted @   空白菌  阅读(74)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示