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

题意

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

思路

堆(优先队列)的做法已经众所周知,复杂度是不可避免的 O ( n l o g n ) 。但如果用单调队列,可以在 O ( n ) 的复杂度中解决。
不难发现,每次合并产生的代价总是单调不减的,那我们可以考虑开另一个队列 b 。一开始从排序后的 a 队列中取两个队首最小元素,并将其推入 b 队列。以后每次都从 a 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;
}

猜你喜欢

转载自blog.csdn.net/Paulliant/article/details/81175392