牛客多校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;
    }
    
    
posted @ 2021-08-17 20:05  ~K2MnO4  阅读(102)  评论(0)    收藏  举报