POJ3253 题解

185 阅读1分钟

题目链接

思路

刚开始想到按长短排序,从长到短依次割。但这样不如从中间某个位置割开之后再分开割,会造成很多浪费。白书给的思路是最后割的一定是最小的两个。证明如下:
如果最后割的不是最小的两个,那么长的这些都会在之前所有的切割中产生代价,必定比把两个小的留到最后产生的多,不会成为最优解。
因此可以倒着做,把小木板拼成刚开始的大木板,每次取最小的两个,并根据他们的和维护ans,维护后把他们拼成一个加入整体继续计算,直到只剩下一个木板。使用优先队列构造小顶堆可以将复杂度优化到O(nlogn)O(nlogn)

#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();
}