1. 程式人生 > 其它 >[NOIP2012]借教室

[NOIP2012]借教室

連結:https://ac.nowcoder.com/acm/problem/16564
來源:牛客網

題號:NC16564
時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 131072K,其他語言262144K
64bit IO Format: %lld
題目描述 
    在大學期間,經常需要租借教室。大到院系舉辦活動,小到學習小組自習討論,都需要向學校申請借教室。教室的大小功能不同,借教室人的身份不同,借教室的手續也不一樣。

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

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

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

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

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



輸入描述:
第一行包含兩個正整數n, m,表示天數和訂單的數量。

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

接下來有m行,每行包含三個正整數dj, sj, tj,表示租借的數量,租借開始、結束分別在第幾天。

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

輸出描述:
如果所有訂單均可滿足,則輸出只有一行,包含一個整數0。否則(訂單無法完全滿足)輸出兩行,第一行輸出一個負整數
-1,第二行輸出需要修改訂單的申請人編號。 示例1 輸入 複製 4 3 2 5 4 3 2 1 3 3 2 4 4 2 4 輸出 複製 -1 2 說明 第1 份訂單滿足後,4 天剩餘的教室數分別為0,323。 第2 份訂單要求第2 天到第4 天每天提供3 個教室,而第3 天剩餘的教室數為2,因此無法滿足。分配停止,通知第2個申請人修改訂單。 備註: 對於10%的資料,有1≤n,m≤10; 對於30%的資料,有1≤n,m≤1000; 對於70%的資料,有1≤n,m≤105; 對於100%的資料,有1≤n, m≤1000000, 0≤ri, dj≤1000000000, 1≤sj≤tj≤ n。

解題方法是 差分+二分,找出左符合,右不符合的訂單。 兩個特判是最後一個符合和第一個不符合,這個二分是到不了的,所以加了特判。

#include<stdio.h>
#define N 1000005
int a[N],cha[N],tem_cha[N],d[N],s[N],t[N],n,m,l,r,mid;
int xxx(int mid);//計算第Mid個訂單是否滿足 
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]); 
        if(i!=1) cha[i]=a[i]-a[i-1];
    }
    for(int i=1;i<=m;i++) scanf("
%d%d%d",&d[i],&s[i],&t[i]); l=1;r=m;mid=(l+r)/2; if(xxx(r)==1) printf("0"); else if(xxx(l)==0) printf("-1\n1"); else{ while(l!=r-1){ if(xxx(mid)) l=mid; else r=mid; mid=(l+r)/2; } printf("-1\n%d",r); } return 0; } int xxx(int mid){ int tem=a[1]; for(int i=1;i<=n;i++) tem_cha[i]=cha[i];//初始差分列表 for(int i=1;i<=mid;i++){//差分列表改變 tem_cha[s[i]]-=d[i]; tem_cha[t[i]+1]+=d[i]; } for(int i=1;i<=n;i++){//比較第Mid單是否夠 tem+=tem_cha[i]; if(tem<0) return 0;//教室不夠了 } return 1; }