Gym - 101911A "Coffee Break"
题意:
Monocarp得到一份工作,每天要工作 m 分钟,他有一个爱好,喜欢在休息的时候喝咖啡,但是他的老板不乐意了,就给他规定了个
时间 d,在 d 分钟内只能喝一杯咖啡。
现给出Monocarp喝 n 杯咖啡的时间点,问最少需要几天喝完?
并输出每个时间点的咖啡在第几天喝。
样例1解释:
4 5 3
3 5 1 2
Monocarp有 n 杯咖啡需要喝,但老板规定,在 3 分钟内只能喝一杯,
那么在第一天Monocarp可以喝时间点为 1,5 的咖啡;
第二天可以喝时间点为 2 的咖啡;
第三天可以喝时间点为 3 的咖啡;
那么,最少需要三天才能喝完这 n 杯咖啡 ;
第一杯咖啡 3 在第三天喝,输出 3;
第二杯咖啡 5 在第一天喝,输出 1;
第三杯咖啡 1 在第一天喝,输出 1;
第四杯咖啡 2 在第二天喝,输出 2;
题解:
根据贪心的思想,对于每一天,尽可能的多喝,这样才会使中天数最少;
首先将咖啡按时间点从小到大排个序,然后找出第一天最多喝的咖啡,第二天最多和的咖啡,以此类推,
直到所有咖啡全部喝完。
那么该怎么找第一天最多和的咖啡呢?
这里我使用了一个 map 中的 lower_bound() 函数,首先将喝咖啡的 n 个时间点存在 map 的first中。根据 map 的特性,
他会自动按照 first值 由小到大排序。
由贪心思想可得,时间点最小(假设为 x)的咖啡要在第一天喝,然后,在 map 中二分查找时间点 ≥ x+d+1 的最小的时刻(假设为 y),
那么 y 时刻的咖啡也要在第一天喝,接着查找时间点 ≥ y+d+1 的最小时刻,以此类推,直到搜索完所有满足条件的时间点,那么第一天的
喝咖啡的时间点就搜索完毕了,并且,在确定某一时间点在第一天喝后,要将其从 map 数组中删去,防止后面的重复计数。
第二天、第三天的搜索情况同理。
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<map> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 const int maxn=2e5+50; 8 9 int n,m,d; 10 int a[maxn]; 11 map<int ,int >ans;//if ans[x]=y : 时间点为x的咖啡在第y天喝 12 map<int ,int >b;//first存储咖啡时间点,second随意 13 14 void Solve() 15 { 16 for(int i=1;i <= n;++i) 17 b[a[i]]=i; 18 19 int day=0; 20 int tot=0; 21 map<int ,int >::iterator it; 22 23 for(it=b.begin();it != b.end();++it) 24 { 25 //当前有tot个时间点已求出解 26 if(tot >= n) 27 break; 28 29 int x=it->first; 30 if(!ans.count(x))//如果在之前的day中没有筛去x时间点,那么x时间点在第day+1天喝 31 { 32 ans[x]=++day; 33 tot++; 34 } 35 //查找出第day天可以喝的咖啡时间点 36 map<int ,int >::iterator t=b.lower_bound(x+d+1); 37 while(t->first >= x+d+1) 38 { 39 ans[t->first]=ans[x]; 40 x=t->first; 41 b.erase(t); 42 43 t=b.lower_bound(x+d+1); 44 tot++; 45 } 46 } 47 48 printf("%d\n",day); 49 for(int i=1;i <= n;++i) 50 printf("%d ",ans[a[i]]); 51 } 52 int main() 53 { 54 scanf("%d%d%d",&n,&m,&d); 55 for(int i=1;i <= n;++i) 56 scanf("%d",a+i); 57 Solve(); 58 59 return 0; 60 }