Codeforces Round - 509C Coffee Break(优先队列贪心模拟)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kuronekonano/article/details/82904163

在这里插入图片描述

题意: 有n个喝咖啡的时间,每天只有m的时间工作,两次喝咖啡的时间间隔必须大于等于d分钟,要把所有n个咖啡时间都喝掉最少需要几天

题解: 首先大体思路是,将咖啡时间按从小到大排序,可以明确的是,因为要保证两两相邻的喝咖啡时间要遵守大于等于d的限制,因此必须合理安排使得任意两个间隔小于d的喝咖啡时间错开。想到这样的方法,取出一个最小时间,可以在第一天喝,取出一个次小时间,若与第一天中的最后一次喝咖啡时间间隔大于等于d,那么这次可以在第一天内喝掉,不用在下一天喝,否则只能错开在下一天喝。
因为要喝掉一次咖啡时间肯定选择已使用天数中截止时间最小的,这样才能保证最大化的利用每天的时间,所以优先队列维护top使其作为每次更新的那一天的进行时间。
如果连top的时间都无法容纳下当前遍历的咖啡时间,那么说明需要新开一天,并且,每次弹出超过一天工作时间的天数。

#include<bits/stdc++.h>
#define LL long long
#define M(a,b) memset(a,b,sizeof a)
#define pb(x) push_back(x)
using namespace std;
const int maxn=2e5+7;
struct node
{
    int pos,ti;
    bool operator <(const node &a)const
    {
        return ti<a.ti;
    }
} a[maxn];
struct days
{
    int day,tim;
    days() {}
    days(int a,int b)
    {
        tim=a,day=b;
    }
    bool operator <(const days &a)const
    {
        return tim>a.tim;
    }
};
int n,m,d,ans[maxn];
priority_queue<days>q;
int main()
{
    scanf("%d%d%d",&n,&m,&d);
    for(int i=0; i<n; i++) scanf("%d",&a[i].ti),a[i].pos=i;
    sort(a,a+n);
    int cnt=0;
    for(int i=0; i<n; i++)
    {
        while(!q.empty()&&q.top().tim>=m)q.pop();
        if(i==0||q.top().tim>=a[i].ti)//新开一天
        {
            ans[a[i].pos]=++cnt;
            q.push(days(a[i].ti+d,cnt));
        }
        else
        {
            int tmp=q.top().day;
            q.pop();
            ans[a[i].pos]=tmp;//第pos个咖啡时间在第top天喝掉
            q.push(days(a[i].ti+d,tmp));//更新掉第top天的最新咖啡时间
        }
    }
    printf("%d\n",cnt);
    for(int i=0; i<n; i++)printf("%d%c",ans[i],i==n-1?'\n':' ');
}

/*
10 10 1
10 5 7 4 6 3 2 1 9 8

1 2 3 4 5 6 7 8 9 10
1 2 1 2 1 2 1 2 1 2
*/


猜你喜欢

转载自blog.csdn.net/kuronekonano/article/details/82904163
今日推荐