题解:AT_abc245_e [ABC245E] Wrapping Chocolate
我绝对不会告诉你我打比赛时没做出来这道题。
题目简化:给定每个巧克力和盒子的长宽,已知每个盒子只能放一块巧克力,并且必须保证巧克力能放下,求是否所有巧克力都能放入。
思路:贪心、二分、排序、STL。
首先看到这道题,最容易想到的算法就是暴力枚举。当然这是不可能的。所以时间复杂度只能是 O ( n log 2 ( n ) ) O(n\log_2(n)) O(nlog2(n)) 或 O ( n ) O(n) O(n) 的。
O ( n ) O(n) O(n) 的我是没想出来,但我一看到 log 2 ( n ) \log_2(n) log2(n),瞬间就想到了两个东西:二分和排序。因为二分就需要排序,所以这里肯定两种都用了。
那排序我们只能排序一个量,但题目中有长宽两个变量,我们怎么排序呢?这时,我们就需要 OI 中一个很重要的思想:化二维为一维。
我们可以这么干:首先按照长排序(具体怎么排大家自己想),然后对于每一个巧克力的宽,我们在盒子中找到能包含它的,全部推入一个数组中,接着对这个数组二分找第一个能容下它的。这一步是贪心,想必大家都能想明白。
最后,如果没有能容下这块巧克力的盒子,直接输出 No
就对了。如果能装下,只需要把这个盒子弹出就行了。(这里就需要思考如何排序了。)
问题:二分需要排序,而快排是 O ( n log 2 ( n ) ) O(n\log_2(n)) O(nlog2(n)) 的,这样一循环不就超时了吗?很简单,只需要用 multiset
就好了,它的排序是 O ( log 2 ( n ) ) O(\log_2(n)) O(log2(n)) 级别的。
AC 代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
struct wc {int x,y;
} a[200006],b[200006];
int n,m;
inline bool cmp(wc x,wc y) {return x.x>y.x;
}
inline bool cmp1(wc x,wc y) {return x.x<y.x;
}
signed main() {cin>>n>>m;for(int i=1; i<=n; i++) {cin>>a[i].x;}for(int i=1; i<=n; i++) {cin>>a[i].y;}for(int i=1; i<=m; i++) {cin>>b[i].x;}for(int i=1; i<=m; i++) {cin>>b[i].y;}sort(a+1,a+n+1,cmp);//具体原因自己想sort(b+1,b+m+1,cmp1);multiset<int>ms;int j=m;for(int i=1; i<=n; i++) {for(; b[j].x>=a[i].x&&j>=1; j--) {ms.insert(b[j].y);}auto it=ms.lower_bound(a[i].y);if(it==ms.end()) {cout<<"No";return 0;}ms.erase(it);//弹出盒子}cout<<"Yes";return 0;
}