P1083 [NOIP2012 提高组] 借教室

 

不要把天数看成一个动态的时间,用数组存储某天原本有多少个教室,表示为第i天原有s[i]个教室.

很容易看出来问题有单调性,所以二分订单数求解.

对于每份订单,其将会使第a天到第b天的教室数量均减少c个.故构造一个差分数组sum,使得sum的前缀和表示对应某天教室数量的变化量.则当天剩余的教室数量为s[i]+(sum[i]的前缀和).

一旦发现某天剩余教室数量小于0,说明不符合,可以很容易写出check函数.

注意如果所有的check都返回了真,最后会有l==m+1,即r保持初始值未变且l增长到r.

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

int n, m, s[1000010];
int sum[1000010];
struct S {
    int d, s, t;
} a[1000010];

bool check(int x) {
    memset(sum, 0, sizeof(int) * (n + 1));
    for (int i = 1; i <= x; i++) {
        sum[a[i].s] -= a[i].d;
        sum[a[i].t + 1] += a[i].d;
    }
    for (int i = 1; i <= n; i++) {
        sum[i] += sum[i - 1];
        if (sum[i] + s[i] < 0) return false;
    }
    return true;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", s + i);
    for (int i = 1; i <= m; i++) scanf("%d%d%d", &a[i].d, &a[i].s, &a[i].t);

    int l = 0, r = m + 1;
    while (l < r) {
        int mid = l + r + 1 >> 1;
        if (check(mid))
            l = mid;
        else
            r = mid - 1;
    }

    if (l == m + 1)
        puts("0");
    else
        printf("-1
%d
", l + 1);

    return 0;
}
P1083
原文地址:https://www.cnblogs.com/Gaomez/p/14258933.html