P1083 借教室
2019-09-14
二分答案是真的妙。
题目描述
在大学期间,经常需要租借教室。大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室。教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。
面对海量租借教室的信息,我们自然希望编程解决这个问题。
我们需要处理接下来n天的借教室信息,其中第i天学校有r_i个教室可供租借。共有m份订单,每份订单用三个正整数描述,分别为d_j,s_j,t_j表示某租借者需要从第s_j天到第t_j天租借教室(包括第s_j天和第t_j天),每天需要租借d_j个教室。
我们假定,租借者对教室的大小、地点没有要求。即对于每份订单,我们只需要每天提供d_j个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。
借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教室。如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。这里的无法满足指从第s_j 天到第t_j天中有至少一天剩余的教室数量不足d_j个。
现在我们需要知道,是否会有订单无法完全满足。如果有,需要通知哪一个申请人修改订单。
Slove
简简单单的二分。
二分天数。
可以的话取右区间。
不可以的话取左区间。
对于区间修改,使用差分就好啦。
Tip
- 二分是真的快,log的。
- 差分是真的快,O(1)的。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1000001
using namespace std; //标准开头
int n,m;
int a[N],f[N];
int d[N],s[N],t[N];
int res[N];
int l,r,mid;
bool sl(int x){
for(int i=1;i<=n;i++) f[i]=a[i]-a[i-1],res[i]=a[i]; //差分
for(int i=1;i<=x;i++){
f[s[i]]-=d[i];
f[t[i]+1]+=d[i];
}
for(int i=1;i<=n;i++){
res[i]=f[i]+res[i-1];
if(res[i]<0) return false;
}
return true;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++) scanf("%d%d%d",&d[i],&s[i],&t[i]);
l=1;r=m;
if(sl(m)){printf("0");return 0;}
while(l<r){
mid=(l+r)/2;
if(sl(mid)) l=mid+1;
else r=mid;
}
printf("-1\n%d",l);
return 0;
}