ZB loves playing StarCraft and he likes Zerg most!
One day, when ZB was playing SC2, he came up with an idea:
He wants to change the queen's ability, the queen's new ability is to choose a worker at any time, and turn it into an egg, after K units of time, two workers will born from that egg. The ability is not consumed, which means you can use it any time without cooling down.
Now ZB wants to build N buildings, he has M workers initially, the i-th building costs t[i] units of time, and a worker will die after he builds a building. Now ZB wants to know the minimum time to build all N buildings.
Input
The first line contains an integer T, meaning the number of the cases. 1 <= T <= 50.
For each test case, the first line consists of three integers N, M and K. (1 <= N, M <= 100000, 1 <= K <= 100000).
The second line contains N integers t[1] ... t[N](1 <= t[i] <= 100000).
Output
For each test case, output the answer of the question.
Sample Input
2 3 1 1 1 3 5 5 2 2 1 1 1 1 10
Sample Output
6 10
Hint
For the first example, turn the first worker into an egg at time 0, at time 1 there’s two worker. And use one of them to build the third building, turn the other one into an egg, at time 2, you have 2 workers and a worker building the third building. Use two workers build the first and the second building, they are built at time 3, 5, 6 respectively.
【题意】:
有m个工人,要造n个建筑,每个工人只能建造一个建筑,每个建筑只能被一个工人造。但是你有一项技能,你可以选择一个工人,把他变成一个蛋,这样k个时间单位后,这个蛋就会孵化出两个工人。
现在给出建造第i栋建筑需要的时间t[i],求建造完这所有n栋建筑需要的时间。
【分析】:由题意知,需要进行n-m次分裂,才能足够人数,也就是在合适的时间进行分裂,使得总耗时最少。
画m个节点在一行上,如果进行分裂,就在该节点下产生两个子节点,边权值为k,表示花了时间k,有点像构造二叉树。
然后把n个建筑往这些节点上凑。建筑接在某节点下,从叶子都根节点的边权和+t[i]就是完成建筑的时间。
由此,要使得这个时间尽量小,利用哈夫曼思想,每次取两个最小的建筑往节点上放,并取大值加上k作为新节点。最后到达根节点的时间最大值一定能保证最小。
用优先队列维护。
【代码】:
#include<stdio.h>
#include<iostream>
#include<queue>
using namespace std;
priority_queue<int,vector<int>,greater<int> >q;
int main()
{
int T,n,m,k,x;
cin>>T;
while(T--)
{
while(!q.empty())q.pop();
cin>>n>>m>>k;
for(int i=0;i<n;i++)
{
scanf("%d",&x);
q.push(x);
}
while(n>m)//人不够,还要分裂
{
q.pop();
int t=q.top();q.pop();
q.push(t+k);
n--;
}
int ans;
while(!q.empty())
{
ans=q.top();q.pop();
}
cout<<ans<<endl;
}
}