描述见题面
思路:直接二分是在第几个订单结束的,最后检验一下二分出来的答案可不可行
检验思路:使用差分,将前k个(k是二分出来的答案)订单的起始,终止位置之间的所有数减去所需的教室数,最后做一遍前缀和,看是否有
哪一天的教室数量小于0,若有小于0的则不能完成订单
代码:
#include <iostream> using namespace std; const int N = 1000010; int a[N]; // 表示每天有多少教室 int b[N]; // 拷贝数组 int n, m; struct order // 使用结构体存储每一个订单的信息 { int count, start, end; }order[N]; bool check(int k) { for (int i = 1; i <= n; i ++ ) b[i] = a[i]; // 拷贝差分数组以供每次使用 for (int i = 1; i <= k; i ++ ) { int l = order[i].start, r = order[i].end, cnt = order[i].count; b[l] -= cnt; b[r + 1] += cnt; } long long res = 0; for (int i = 1; i <= n; i ++ ) { res += b[i]; if (res < 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 = n; i >= 1; i -- ) a[i] -= a[i - 1]; for (int i = 1; i <= m; i ++ ) { int a1, a2, a3; scanf("%d%d%d", &a1, &a2, &a3); order[i] = {a1, a2, a3}; } // 二分第几个订单结束 int l = 0, r = m; while (l < r) { int mid = l + r >> 1; if (!check(mid)) r = mid; // 取不到的话k最多就到当前mid else l = mid + 1; // 能取到的话就更进一步试试 } if (check(l)) puts("0"); else printf("-1\n%d\n", l); return 0; }