题目描述:
农夫约翰为了修理栅栏,要将一块很长的木板切割成N块。准备切成的木板的长度为Li。未切割前的长度恰好等于切割后的长度和。每次切断木板,需要的代价都是这块木板的长度。求出符合切割目标的最小开销。
解题思路:
可以倒过来想,把切割想象成木板合成过程,合成的代价就是新木板的长度,这样就是典型的合并果子的贪心问题了,对于数据的处理,如果每次合并完后都进行快排的话时间肯定不够用,那么可以用一个优先队列来维护。
当然还可以用双队列来维护,用一个队列a记录原来木板的长度,用b队列记录每次合成的新木板的长度,每次从a和b中取出两个最小的元素合成,然后把新木板放到b中,直到b中只有一个木板。
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
intn,a[20010],b[20010],la=0,lb=0,ra=-1,rb=-1;
void solve(){
long long ans=0;
while (ra>=la||rb>lb){
long long tmp=0;
if (ra>=la){
if (rb<lb||a[la]<b[lb]) tmp+=a[la++];
else tmp+=b[lb++];
}
else tmp+=b[lb++];
if (ra>=la){
if (rb<lb||a[la]<b[lb]) tmp+=a[la++];
else tmp+=b[lb++];
}
else tmp+=b[lb++];
ans+=tmp;
b[++rb]=tmp;
}
cout<<ans<<endl;
}
int main(){
cin>>n;
ra=n-1;
for (int i=0;i<n;i++) scanf("%d",&a[i]);
sort(a,a+n);
solve();
}