P1083 借教室
题意:给出n天可供使用的教室,给出m个订单,每个订单为一段连续的天数内使用掉相同数量的教室
订单的处理按先来先处理原则
问:是否能满足所有订单,假如可以的话,输出0
假如不可以的话,就输出-1,并且输出不满足的订单的编号
思路:看到数据很容易就能想到暴力做法,但是暴力做法会超时
所以,我们采用二分的方式,降低复杂度,最终复杂度大概为(n*logn)
那么具体怎么做呢?我们将订单处理用一个差分数组来表示
然后,开始二分枚举哪一次订单不满足,这是满足二分性质的
比如:我们在第6次订单假如不满足的话,那么第七次以及后面的订单也肯定是不满足的,所以就可以在左区间二分
假如满足的话,证明之前的订单全部合起来也都是满足情况的,所以就可以在右区间二分
于是,知道满足二分的做法后,我们来看看如何判定
我们取区间中点,即第mid次订单及其前面所有的订单数据,用差分数组的方式进行处理
然后再看看有没有哪个数会出现负数
如果有负数的情况,证明不满足,反之满足
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e6+10; 4 const int inf=0x3f3f3f3f; 5 int s[maxn],t[maxn],d[maxn]; 6 int a[maxn]; 7 int cf[maxn];int sum; 8 int n,m; 9 int check(int mid) 10 { 11 memset(cf,0,sizeof(cf)); 12 for(int i=1;i<=mid;i++){ 13 cf[s[i]]-=d[i]; 14 cf[t[i]+1]+=d[i]; 15 } 16 int sum=0; 17 for(int i=1;i<=n;i++){ 18 sum+=cf[i]; 19 if(a[i]+sum<0) return 0; 20 } 21 return 1; 22 } 23 int main() 24 { 25 scanf("%d%d",&n,&m); 26 for(int i=1;i<=n;i++) 27 scanf("%d",&a[i]); 28 for(int i=1;i<=m;i++){ 29 scanf("%d%d%d",&d[i],&s[i],&t[i]); 30 } 31 int L=1,R=m; 32 int ans=inf; 33 while(L<=R){ 34 int mid=L+R>>1; 35 if(check(mid)){ 36 L=mid+1; 37 } 38 else{ 39 R=mid-1; 40 ans=mid; 41 } 42 } 43 if(ans==inf) printf("0\n"); 44 else{ 45 printf("-1\n"); 46 printf("%d\n",ans); 47 } 48 return 0; 49 }