牛客多校2021(六)F. Hamburger Steak(贪心)
-
题目: Hamburger Steak
-
题意:给出n个汉堡和m个锅,每个汉堡需要煎的时间为\(t_i\),可以放在其中一个锅煎,或者先放一个锅煎\(t_1\)的时间,再放到另一个锅煎\(t_2\)的时间(满足\(t_1 + t_2 = t_i\)),但要保证这两个锅在煎第\(i\)个汉堡时时间上不能有交集,问煎完所有汉堡需要花费的最少时间(题目要求输出需要锅的数量,还有锅的编号,以及起始时间和结束时间)。
-
题解:
-
若需要求得最少时间,那么尽可能保证在煎的过程中使得每个锅都一直有汉堡被煎(也就是锅不能空),假设当前有三个汉堡两个锅,每个汉堡需要花费的时间均为2分钟,若先将两个煎掉,再煎剩下的一个汉堡,则需要的总时间为4分钟,若先将两个煎1分钟后拿出来,再放剩下未被煎过的汉堡放入锅中煎两分钟,那这时剩下的那个锅就可以煎两个1分钟的汉堡,需要的总时间为3分钟。
-
所以,我们可以构造一种策略:首先固定好每个锅可使用的时间\(T = max(maxt_i, \lceil \frac{\sum_i^nt_i}{n} \rceil)\),取平均值是为了保证所有汉堡能在最短时间内被煎完(若不考虑交集问题,只要\(maxt_i\)比avg小,那必然是可以实现的),而取所有汉堡中花费的最长时间是为了确保存在某个汉堡\(t_i > avg\)时,必然需要使用两个锅,若此时使用平均值作为T,则\(maxt_i\)在第二个锅煎汉堡的时间会与第一个锅的时间有交集(如图1)。然后我们是将花费时间大的汉堡先煎,也就是放入锅中,若该锅还有剩余时间,则继续煎下一个汉堡,若该汉堡仍未被煎完(该锅时间已经被用完),则放入下一个锅煎,这样既做到了使所有锅尽可能的被占用,并且同一汉堡使用两个锅时时间上不会产生交集(如图2)。
图1:

图2:

-
最后就是模拟每个汉堡放入的过程,并注意该汉堡被两个锅煎过需要按照时间的先后顺序来输出。
-
-
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; const int N = 1e5 + 5; typedef long long ll; int n, m; ll sum, avg, maxT = 0; struct Node { int k, cur1, cur2; ll bg1, bg2, ed1, ed2; //开始时间和结束时间 }a[N]; struct Food { ll val; int pos; }t[N]; bool cmp(Food a, Food b) { return a.val > b.val; } int main() { cin >> n >> m; for(int i = 1; i <= n; i++) { cin >> t[i].val; t[i].pos = i; sum += t[i].val; maxT = max(maxT, t[i].val); } avg = (sum + m - 1) / (ll)m //ceil(double(sum) / double(m)); ll T = max(maxT, avg); //一个锅使用的时间 sort(t + 1, t + 1 + n, cmp); int cur = 1; //当前锅编号 int id = 1; //当前汉堡编号 ll head = 0; //头指针 int k = 1; //记录使用锅的数量(默认使用一个锅) while(cur <= m) { int pos = t[id].pos; //原来该汉堡的序号 if(t[id].val <= T - head) //用一个锅 { if(k == 2) //说明需要用两个锅(之前用了一个,现在还需用下一个) a[pos].cur1 = cur, a[pos].bg1 = head, a[pos].ed1 = head + t[id].val; else //仅用一个锅即可 a[pos].k = 1, a[pos].cur1 = cur, a[pos].bg1 = head, a[pos].ed1 = head + t[id].val; head += t[id].val; id ++; k = 1; if(head == T) //当前的锅时间已被耗尽 { head = 0; cur ++; } } else //用两个锅 { k = 2; ll val = T - head; //该汉堡在第一个锅花费的时间 a[pos].k = k, a[pos].cur2 = cur, a[pos].bg2 = head, a[pos].ed2 = T; cur ++; //这个锅能用的时间已经用完 head = 0; t[id].val -= val; //该汉堡还需要花费的时间 } if(id == n + 1) break; } //输出答案 for(int i = 1; i <= n; i++) { if(a[i].k == 1) cout << "1 " << a[i].cur1 << " " << a[i].bg1 << " " << a[i].ed1 << endl; else cout << "2 " << a[i].cur1 << " " << a[i].bg1 << " " << a[i].ed1 << " " << a[i].cur2 << " " << a[i].bg2 << " " << a[i].ed2 << endl; } return 0; }

浙公网安备 33010602011771号