题解 P2920 【 时间管理Time Management】

Rbu_nas

2018-11-24 00:37:24

Solution

本题其实思路很好想,也有很多实现方式。在这里详细介绍一下好写不容易挂的二分答案。 --- 关于二分: **最常见的**模板大概就长这样了 ```cpp //此处l、r需要根据题目要求定义. while(l <= r) { mid=(l+r)>>1; if(check(mid)) ans=mid, l=mid+1; else r=mid-1; } ``` 顾名思义,二分答案枚举的是答案,它的精髓就在于`check`函数了,二分答案又适用于哪些题目呢? - 最大值最小、最小值最大 - 满足条件的第k个数 --- 那么二分答案怎么想,怎么写呢?以本题为例,要求最迟的工作时间x,我们就可以**枚举时间x判断这个时间能否完成任务**,然后不断往后推(因为求最迟的),因而`l=mid+1`,也就是说对于时间x,必须满足**可以完成工作**的条件 很容易想到对它们的截止时间排序,然后依次判断,如果这时的x满足于$x+a_i.t <= a_i.end$ 那么x加上这次完成所需的时间对下一个$a_i$再次判断,`check`函数的思路也就出来了: ```cpp inline bool check(int x) { for(register int i=0; i<n; ++i) { if(x+a[i].t <= a[i].end) x+=a[i].t; /* 如果可以满足要求就加上这次工作的时间 看x下一次是否能满足期限内下个任务要求 */ else return false; } return true; } ``` --- 那么结合刚刚所说的右逼答案此题就很快能写出来了 ```cpp # include <cstdio> # include <cstdlib> # include <iostream> # include <no-copy.h> # include <algorithm> using namespace std; inline void gi(int &x) { x=0;int t=1,k=getchar(); for(;k<'0'||k>'9';k=getchar())if(k=='-')t=-1; for(;k>='0'&&k<='9';k=getchar())x=(x<<1)+(x<<3)+(k^48);x*=t; } const int N=1000+5; int n; struct NODE { int t, end; //t是工作所需的时间,end是截止时间 bool operator < (const NODE &other) const { return end < other.end; } } a[N]; inline bool check(int x) { for(register int i=0; i<n; ++i) { if(x+a[i].t <= a[i].end) x+=a[i].t; else return false; } return true; } int main(void) { gi(n); for(int i=0; i<n; ++i) gi(a[i].t), gi(a[i].end); sort(a, a+n); //对截止时间排序,越早的自然越先做 int l=0, r=a[n-1].end+5, mid, ans=-1; /* r根据题目要求取一个不可取的值,这里取的是最晚的截止日期,因为显然不可能此时完成工作 如果无解输出-1,所以直接把ans设为-1,如果没有时间x满足要求就直接输出-1了 */ while(l <= r) { mid=(l+r)>>1; if(check(mid)) //每次枚举时间x看看是否能从第x分钟开始做完成任务 ans=mid, l=mid+1; else r=mid-1; } printf("%d", ans); return 0; } ``` 本题的`check`思路很简单,大家也可以做做[木材加工](https://www.luogu.org/problemnew/show/P2440)、[砍树](https://www.luogu.org/problemnew/show/P1873)练练手 如果有帮助的话请扣个赞QwQ,有问题欢迎在评论指出或提问