[NOIP2012 提高組] 借教室

土木牢盖發表於2024-11-24

[NOIP2012 提高組] 借教室

題目描述

在大學期間,經常需要租借教室。大到院系舉辦活動,小到學習小組自習討論,都需要向學校申請借教室。教室的大小功能不同,借教室人的身份不同,借教室的手續也不一樣。

面對海量租借教室的資訊,我們自然希望程式設計解決這個問題。

我們需要處理接下來 \(n\) 天的借教室資訊,其中第 \(i\) 天學校有 \(r_i\) 個教室可供租借。共有 \(m\) 份訂單,每份訂單用三個正整數描述,分別為 \(d_j,s_j,t_j\),表示某租借者需要從第 \(s_j\) 天到第 \(t_j\) 天租借教室(包括第 \(s_j\) 天和第 \(t_j\) 天),每天需要租借 \(d_j\) 個教室。

我們假定,租借者對教室的大小、地點沒有要求。即對於每份訂單,我們只需要每天提供 \(d_j\) 個教室,而它們具體是哪些教室,每天是否是相同的教室則不用考慮。

借教室的原則是先到先得,也就是說我們要按照訂單的先後順序依次為每份訂單分配教室。如果在分配的過程中遇到一份訂單無法完全滿足,則需要停止教室的分配,通知當前申請人修改訂單。這裡的無法滿足指從第 \(s_j\) 天到第 \(t_j\) 天中有至少一天剩餘的教室數量不足 \(d_j\) 個。

現在我們需要知道,是否會有訂單無法完全滿足。如果有,需要通知哪一個申請人修改訂單。

輸入格式

第一行包含兩個正整數 \(n,m\),表示天數和訂單的數量。

第二行包含 \(n\) 個正整數,其中第 \(i\) 個數為 \(r_i\),表示第 \(i\) 天可用於租借的教室數量。

接下來有 \(m\) 行,每行包含三個正整數 \(d_j,s_j,t_j\),表示租借的數量,租借開始、結束分別在第幾天。

每行相鄰的兩個數之間均用一個空格隔開。天數與訂單均用從 \(1\) 開始的整數編號。

輸出格式

如果所有訂單均可滿足,則輸出只有一行,包含一個整數 \(0\)。否則(訂單無法完全滿足)

輸出兩行,第一行輸出一個負整數 \(-1\),第二行輸出需要修改訂單的申請人編號。

樣例

樣例輸入

4 3 
2 5 4 3 
2 1 3 
3 2 4 
4 2 4

樣例輸出

-1 
2

提示

【輸入輸出樣例說明】

第 $1 $份訂單滿足後,$4 $天剩餘的教室數分別為 \(0,3,2,3\)。第 \(2\) 份訂單要求第 $2 $天到第 \(4\) 天每天提供$ 3 $個教室,而第 \(3\) 天剩餘的教室數為$ 2$,因此無法滿足。分配停止,通知第\(2\) 個申請人修改訂單。

【資料範圍】

對於10%的資料,有\(1≤ n,m≤ 10\)

對於30%的資料,有\(1≤ n,m≤1000\)

對於 70%的資料,有\(1 ≤ n,m ≤ 10^5\)

對於 100%的資料,有\(1 ≤ n,m ≤ 10^6,0 ≤ r_i,d_j≤ 10^9,1 ≤ s_j≤ t_j≤ n\)

[!TIP]

隨訂單增加,所需教室數單調遞增→二分查詢
教室數在訂單區間中→差分陣列

注意開long long,否則會部分WA

#include <bits/stdc++.h>
using namespace std;

const int N = 1000005;
int n, m, ans;
int a[N], d[N], s[N], t[N];
bool found = false;

bool check(int mid) {
    long long baka[N] = {0}; //差分陣列
    long long fumo = 0;//注意要開loang long 不然會部分WA

    for(int i = 1; i <= mid; i++) 
    {
        baka[s[i]] += d[i];
        baka[t[i] + 1] -= d[i];
    }

    for(int i = 1; i <= n; i++) 
    {
        fumo += baka[i];
        if(fumo > a[i]) 
        return true;
    }
    return false;
}

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++){
    scanf("%d", &a[i]);}
    for(int i = 1; i <= m; i++){
    scanf("%d%d%d", &d[i], &s[i], &t[i]);}
    
    int l = 1, r = m, mid;
    while(l <= r) {
        mid = (l + r) >> 1;
        if(check(mid))
        {
            ans = mid;//不記錄 ans,當 check(mid) 返回 true 時,無法知道之前哪些 mid 滿足條件,從而導致部分 WA,透過記錄 ans,我們可以確保在找到第一個不滿足條件的 mid 之前,已經記錄了最後一個滿足條件的 mid
            found = true;
            r = mid - 1;
        } else {
            l = mid + 1;
        }
    }
    if(found) printf("-1\n%d", ans);
    else printf("0");
    return 0;
}


相關文章