思路
刚开始想到按长短排序,从长到短依次割。但这样不如从中间某个位置割开之后再分开割,会造成很多浪费。白书给的思路是最后割的一定是最小的两个。证明如下:
如果最后割的不是最小的两个,那么长的这些都会在之前所有的切割中产生代价,必定比把两个小的留到最后产生的多,不会成为最优解。
因此可以倒着做,把小木板拼成刚开始的大木板,每次取最小的两个,并根据他们的和维护ans,维护后把他们拼成一个加入整体继续计算,直到只剩下一个木板。使用优先队列构造小顶堆可以将复杂度优化到
#include<iostream>
#include<algorithm>
#include<queue>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
using namespace std;
const int N=2E4+10;
int n;
long long ans;
priority_queue<int,vector<int>,greater<int> > q;
inline int read()
{
int ret=0;char ch=getchar();
while(ch<'0' || ch>'9')
ch=getchar();
while(ch>='0' && ch<='9')
{
ret=ret*10+ch-'0';
ch=getchar();
}
return ret;
}
void solve()
{
while(!q.empty())
{
if(q.size()==1)
{
break;
}
int fir=q.top();q.pop();
int sec=q.top();q.pop();
int sum=fir+sec;
ans+=sum;
q.push(sum);
}
cout<<ans<<endl;
}
int main()
{
n=read();
rep(i,1,n)
{
q.push(read());
}
solve();
}