题解 P1083 【借教室】

· · 题解

安利一发自己的博客:http://www.cnblogs.com/OIerShawnZhou/

(我平常写的题解都会往博客里发,欢迎各位大佬前来拍砖)

这是一道用前缀和与二分瞎搞的题。

我们知道所有的订单,并且题目规定了所有订单必须从前往后依次处理。

题目要求输出最前面一个需要修改的订单号。

之前我们说,可以二分的题目需要满足解的有界性和单调性,此题显然满足。

有界性,需要修改的订单一定出现在[1,m]之间。

单调性,这是题目给的已知条件。

所以可以使用二分答案来求解这道题。

显然,它可以被认为是求“最大值最小”的问题。

我们在[1,m]上对答案进行二分,并且就暂且认为这一天会出问题。

那么如何判断这一天有没有出问题呢?

需要预处理一个前缀和数组sum,用来维护[1,mid]之间的需要房间总数。

这里可能不好想,对于一个sum,我们用order[i].st代表第i个订单的开始时间,order[i].ed为终止时间,order[i].room_num为这个订单内每天需要的房间数。

于是有

sum[order[i].st] += order[i].room_num;

sum[order[i].ed+1] -= order[i].room_num;

(对于i∈[1,mid])

即开始在订单内的某天加上这一天所需要的房间数

订单外后的下一天减去那一天需要的房间数(因为这个时候已经借完了)

这时我们就处理好了某一天需要的总房间数。那么,枚举所有订单,寻找第一个不合法的订单,如果找到了不合法订单就返回true。所有订单都合法就返回false。

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define maxn 1000005
using namespace std;
struct orders{
    int room_num;
    int st;
    int ed;
};
orders order[maxn];
int n,m;
int room_limit[maxn];
int l,r,mid;
int sum[maxn];
int read(){
    int num = 0;
    char c;
    bool flag = false;
    while ((c = getchar()) == ' ' || c == '\n' || c == '\r');
    if (c == '-')
        flag = true;
    else
        num = c - '0';
    while (isdigit(c = getchar()))
        num = num * 10 + c - '0';
    return (flag ? -1 : 1) * num;
}

bool judge(int mid){
    memset(sum,0,sizeof(sum));
    for (register int i=1;i<=mid;i++){
        sum[order[i].st] += order[i].room_num;
        sum[order[i].ed+1] -= order[i].room_num;
    }
    for (register int i=1;i<=n;i++){
        sum[i]+=sum[i-1];
        if (sum[i]>room_limit[i])
            return true;
    }

    return false;
}

int main(){
    n = read();m = read();
    for (register int i=1;i<=n;i++)
        room_limit[i] = read();
    for (register int i=1;i<=m;i++){
        order[i].room_num = read();
        order[i].st = read();
        order[i].ed = read();
    }
    l=1;r=m;
    while (l<r){
        mid=(l+r) >> 1;
        if (judge(mid))
            r=mid;
        else l=mid+1;
    }    
    if (m!=r) 
        printf("-1\n%d",r);

    else 
        printf("0\n");
    return 0;
}