[NOIp2012] 借教室

类型:二分答案+差分

传送门:>Here<

题意:学校规定第$i$天只能借$r[i]$间教室。现给出$M$个订单,每个订单描述要在$s[i]$到$t[i]$期间每天借$d[i]$间教室。原则是先到先得,问第一个无法满足的订单是第几个?

解题思路

这题暴力分很好拿呀……打了10分钟拿到30分。后来发现数组开小了,改大之后竟然变成了45分!这题的暴力是PJ-难度啊……

然后偷看一眼标签马上知道了二分答案,但是要做到$O(n)$验证,前缀和的空间复杂度是$mn$的啊……然后突然之间想到,不需要对每一天维护前缀和,只需要维护一个差分数组就好了!于是AC

希望今年也能碰到这样的良心题啊!(样例并不良心)

Code

/*By DennyQi 2018.8.16*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define  r  read()
#define  Max(a,b)  (((a)>(b)) ? (a) : (b))
#define  Min(a,b)  (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int MAXN = 1000010;
const int MAXM = 27010;
const int INF = 1061109567;
inline int read(){
    int x = 0; int w = 1; register int c = getchar();
    while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
    if(c == '-') w = -1, c = getchar();
    while(c >= '0' && c <= '9') x = (x<<3) + (x<<1) + c - '0', c = getchar();return x * w;
}
int N,M,flg,L,R,Mid,Ans;
int a[MAXN],d[MAXN],s[MAXN],t[MAXN],cf[MAXN];
inline bool judge(int k){
    int u = 0;
    memset(cf, 0, sizeof(cf));
    for(int i = 1; i <= k; ++i){
        cf[s[i]] -= d[i];
        cf[t[i]+1] += d[i];
    }
    for(int i = 1; i <= N; ++i){
        u += cf[i];
        if(u+a[i] < 0) return 1;
    }
    return 0;
}
int main(){
    N = r, M = r;
    for(int i = 1; i <= N; ++i) a[i] = r;
    for(int i = 1; i <= M; ++i) d[i] = r, s[i] = r, t[i] = r;
    L = 0, R = M+1;
    while(L <= R){
        Mid = (L+R) / 2;
        if(judge(Mid)) R = Mid - 1;
        else Ans = Mid, L = Mid+1;
    }
    if(Ans+1 <= M) printf("-1
%lld", Ans+1);
    else printf("0");
    return 0;
}
原文地址:https://www.cnblogs.com/qixingzhi/p/9485234.html