Wrapping Chocolate(multiset、貪心)
阿新 • • 發佈:2022-03-27
題意
給定\(n\)個巧克力,對於第\(i\)個巧克力,其寬是\(A_i\),長是\(B_i\)。
給定\(m\)個盒子,對於第\(i\)個盒子,其寬是\(C_i\),長是\(D_i\)。
若第\(i\)個巧克力能被第\(j\)個盒子裝下,需要滿足\(A_i \leq C_j\),並且\(B_i \leq D_j\)。
每個盒子最多隻能裝一個巧克力。
問所有巧克力是否都能被裝下?
資料範圍
\(1 \leq n \leq m \leq 2 \times 10^5\)
思路
首先這個題目一個初步的想法就是,巧克力和盒子都先按照寬從小到大排序。然後利用雙指標,\(i\)表示當前掃描到的巧克力,\(j\)
但是此時,下標從\(j\)到\(m\)的盒子的長是無序的,無法處理。那麼,有沒有什麼方法可以自動排序呢,可以想到的是multiset。
這樣的話,還是不好維護,因為隨著\(j\)向後移動,multiset會不知道該彈出哪個元素。
那麼,可以從大到小列舉,這樣會將元素加入multiset中,而不是彈出。對於每個巧克力,找到multiset中滿足要求的長中最小值,將其彈出即可。如果長的最大值也無法滿足要求,那麼當前的巧克力就不能被裝下。
這裡官方題解給出的方法大致相同,但是思路更加清晰。
將巧克力和盒子放在一起,按照寬從大到小排序,如果巧克力和盒子的寬相等,那麼將盒子排在前面。
掃描這個序列,同時維護一個multiset。如果當前掃描到的是盒子,那麼就將其長加入multiset中;如果是巧克力,找到滿足要求的長的最小值,並彈出。如果找不到,則不能被裝下。
注:multiset中維護的其實是寬滿足要求的盒子的長。
程式碼
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <set> using namespace std; const int N = 400010; int n, m; struct Item { int w, l, type; bool operator < (const Item &t) const { if(w == t.w) return type < t.type; return w < t.w; } }a[N]; multiset<int> b; int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= n; i ++) scanf("%d", &a[i].w); for(int i = 1; i <= n; i ++) scanf("%d", &a[i].l); for(int i = 1; i <= n; i ++) a[i].type = 1; for(int i = n + 1; i <= n + m; i ++) scanf("%d", &a[i].w); for(int i = n + 1; i <= n + m; i ++) scanf("%d", &a[i].l); for(int i = n + 1; i <= n + m; i ++) a[i].type = 2; sort(a + 1, a + n + m + 1); for(int i = n + m; i >= 1; i --) { auto t = a[i]; if(t.type == 2) b.insert(t.l); else { int p = t.l; auto loc = b.lower_bound(p); if(loc == b.end()) { printf("No\n"); return 0; } b.erase(loc); } } printf("Yes\n"); return 0; }