1. 程式人生 > 實用技巧 >P1083 [NOIP2012 提高組] 借教室

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\n%d\n", l + 1); return 0; }
P1083