CSU-1588 合并果子(堆/单调队列)

本文介绍了一种求解最小合并代价问题的高效算法,利用单调队列实现O(n)的时间复杂度,通过逐步合并果子堆并计算总代价,提供了一个具体的C++实现代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

n n 堆果子,第 i 堆果子有 ai a i 个,每次合并的代价是两堆果子个数的总和,求总合并的最小代价。
1n1000 1 ≤ n ≤ 1000

思路

堆(优先队列)的做法已经众所周知,复杂度是不可避免的 O(nlogn) O ( n l o g n ) 。但如果用单调队列,可以在 O(n) O ( n ) 的复杂度中解决。
不难发现,每次合并产生的代价总是单调不减的,那我们可以考虑开另一个队列 b b 。一开始从排序后的 a 队列中取两个队首最小元素,并将其推入 b b 队列。以后每次都从 a b b 队首分别去出两个较大的元素,并累计代价再插入 b 队列尾。

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
#define N 1003
typedef long long LL;
using namespace std;
int a[N],b[N];

int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        int ans=0;
        scanf("%d",&n);
        FOR(i,1,n)scanf("%d",&a[i]);
        int al=1,ar=n,bl=1,br=0;
        sort(a+1,a+1+n);
        FOR(i,2,n)
        {
            int ele=0;
            if(bl>br||al<=ar&&a[al]<b[bl])
                ele+=a[al++];
            else if(bl<=br)
                ele+=b[bl++];
            if(bl>br||al<=ar&&a[al]<b[bl])
                ele+=a[al++];
            else if(bl<=br)
                ele+=b[bl++];
            ans+=(b[++br]=ele);
        }
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值