FZU 2219 StarCraft(星际争霸)

Description

题目描述

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.

ZB喜欢玩星际争霸并且他爱用虫族!

有一天,在ZB玩星际争霸2的时候,脑洞乍开:

他想改变女王的技能,女王的新技能可以在任何时候指定一只农民,使其变成一个虫卵,K个单位时间后,两只农民将被孵化出来。此技能没有消耗,意味着你不需要担心冷却时间。

ZB想建N个建筑,他有M个初始农民,第i个建筑需要t[i]个单位时间,并且农民在完成建筑后立即死亡。现在ZB想知道建完全部N个建筑的最短时间。

 

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).

输入的首行是一个整数T,表示测试样例的数量。1 <= T <= 50。

对于每个测试样例,第一行有3个整数N,M和K。(1 <= N, M <= 100000, 1 <= K <= 100000)。

第二行有N个整数t[1] ... t[N](1 <= t[i] <= 100000)。

 

Output

输出

For each test case, output the answer of the question.

对于每个测试样例,输出问题的答案。

 

Sample Input - 输入样例

Sample Output - 输出样例

2

3 1 1

1 3 5

5 2 2

1 1 1 1 10

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.

对于第一个例子,在0时刻选择农民变虫卵,在1时刻有2个农民。然后用一个去建第三个建筑,另一个变成虫卵。

在2时刻,你有2个农民,并且第三个建筑正在建造。用两个农民分别建造第一和第二个建筑,他们会在时刻3,5,6分别完成。

 

【题解】

类似哈夫曼树的合并方式,对于当个农民(工蜂)来说,算上分裂技能,建造是不断两两并行的,建造时间越小,合并的价值就越小。合并后的时间去被合并两者的较大值+K。初始农民的数量就是合并的终点。

然后问题可以化成,给你一堆数字,每次把次小值+K,再删除当前最小值,直到剩下M个数字。

【代码 C++】

multiset会超时,还是用优先队列吧,默认排序的大根堆,改成小根堆就好了。

代码只是为了简洁与能过,想要理想的效率还是要经过进一步的优化。

 1 #include<cstdio>
 2 #include<queue>
 3 #include<functional>
 4 std::priority_queue<int, std::vector<int>, std::greater<int> > data;
 5 int main(){
 6     int t, N, M, K, i, j;
 7     scanf("%d", &t);
 8     while (t--){
 9         scanf("%d%d%d", &N, &M, &K);
10         for (i = 0; i < N; ++i) scanf("%d", &j), data.push(j);
11         while (N > M){
12             data.pop();
13             data.push(data.top() + K);
14             data.pop();
15             --N;
16         }
17         while (data.size() != 1) data.pop();
18         printf("%d\n", data.top());
19         data.pop();
20     }
21     return 0;
22 }

FZU 2219
 

转载于:https://www.cnblogs.com/Simon-X/p/5143228.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值