【每日一题】7月1日题目精讲 借教室
來源:牛客網
時間限制: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
輸入
復制
輸出
復制
說明
第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≤105;
對于100%的數據,有1≤n, m≤106, 0≤ri, dj≤109, 1≤sj≤tj≤ n。
題解:
noip原題
第一反應線段樹,不過線段樹懶得打,我們用其他方法
差分+二分
差分:
我們都知道前綴和,所謂差分簡單理解就是前綴和的逆運算
前綴和:
其中數組a可以看做是相鄰sum數組的差值
差分:
差分就是給你相鄰的差值,然后求出每一項
前綴和是用元數據求元與元之間的并集關系,而差分則是根據元與元之間的邏輯關系求元數據,是互逆思想
二分:
這個題為什么能用二分呢?
二分的條件:狀態的決策過程或者序列是否滿足單調性或者可以局部舍棄性
如果第x個訂單無法滿足,那x之后的就都不用看了,我們要找的答案就一定在x之前,如果x能滿足,答案就在x之后,這不就是典型的二分嗎?
整合
dif[l[i]]+=d[i]; dif[r[i]+1]-=d[i];我們在讀入時是 d l r,分別表示數量和時間范圍
dif[x]+=d 可以理解為第x天之后(含第x天)的每天都需要數量為d的教室,為什么?看一下下面的代碼,need[i]表示第i天的需求,need是由dif推導出來的,也就是dif[i]的結果會影響到第i天之后的每一個need,這樣我們就可以通過改變dif來實現操作區間
但是我們數量d的范圍是[l,r],所以還要加一個dif[r[i]+1]-=d[i],也就是第r+1天之后的數量減d,這樣就和之前加d的影響給抵消了,最終效果只體現在區間[l,r]
代碼:
#include<bits/stdc++.h> using namespace std; int n,m; const int maxn=1e6+3; int dif[maxn],need[maxn]; int a[maxn]; int d[maxn],l[maxn],r[maxn]; bool isok(int x) {memset(dif,0,sizeof(dif));for(int i=1;i<=x;i++){dif[l[i]]+=d[i];dif[r[i]+1]-=d[i];}for(int i=1;i<=n;i++){need[i]=need[i-1]+dif[i];if(need[i]>a[i])return 0;//供不應需 ,教室不夠 }return 1; } int main() {cin>>n>>m;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=m;i++)cin>>d[i]>>l[i]>>r[i];int l=1,r=m;if(isok(m)){return cout<<"0", 0;}while(l<r){int mid=(l+r)>>1;if(isok(mid))//當前情況可以 l=mid+1; else //當前情況不可以r=mid; }printf("-1\n%d",l);return 0; }總結
以上是生活随笔為你收集整理的【每日一题】7月1日题目精讲 借教室的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: QoS怎么设置 小米路由器QoS智能限速
- 下一篇: lxde桌面美化怎么样?选择LXDE作为