AtCoder Regular Contest 076 F - Exhausted? (贪心)
题面
题解
如果只有 l l l 的限制,那么肯定直接按照 l l l 从小到大排序,然后从左边的椅子依次开始填就完了,就是道贪心板题了。
但是这题同时限制了 l l l 和 r r r 怎么办呢,它直接进化成黑题了。
我们不妨先按照 l l l 贪心,然后给 r r r 一个反悔的机会。
有点抽象,具体的做法是:
我们仍然按照 l l l 排序(从小到大,如前文所述),每次选最小的没有被占据的,如果没有这样的位置,那么就考虑把之前的一个人“替换”出来,需要被替换出来的人的 r r r 比当前的 r r r 小(这样替换出来才有更多的选择空间),如果有多个满足要求显然应该替换 r r r 最小的出来。
操作完之后还剩下若干个人(被“替换”出来或是“替换”失败的倒霉蛋),并且此时被占据的位置一定是个前缀,因此我们按(剩余人的) r r r 从大到小排序再贪心即可(从右边的椅子开始填),此时坐不下的人就没办法了。
看到上面的“显然”就知道肯定不是笔者说的, 上面的做法出自wzy大神的讲评,感觉还是很好理解的(我只解释了四个地方)。
因此只需要做
l
l
l 时用一个小根堆维护
r
r
r 最小的人,其次要注意一个细节,后面贪心
r
r
r 的时候不能坐到前面贪
l
l
l 时坐满的位置。
CODE
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define LL long long
#define DB double
#define ENDL putchar('\n')
LL read() {
LL f=1,x=0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
int n,m,i,j,s,o,k;
struct it{
int l,r; it(){l=r=0;}
it(int L,int R){l=L;r=R;}
}a[MAXN];
bool cmp(it a,it b) {return a.l < b.l;}
bool operator < (it a,it b) {return a.r < b.r;}
bool operator > (it a,it b) {return b < a;}
priority_queue<it,vector<it>,greater<it> > b1;
priority_queue<it> b2;
int main() {
n = read();m = read();
for(int i = 1;i <= n;i ++) {
a[i].l = read();a[i].r = read();
}
sort(a + 1,a + 1 + n,cmp);
int le = 0;
b1.push(it(0,m+1));
for(int i = 1;i <= n;i ++) {
if(le < a[i].l) {
le ++;
b1.push(a[i]);
}
else {
if(a[i].r > b1.top().r) {
b2.push(b1.top());
b1.pop(); b1.push(a[i]);
}
else b2.push(a[i]);
}
}
int ans = 0,le2 = m+1;
while(!b2.empty()) {
it t = b2.top(); b2.pop();
if(le2 > max(t.r,le+1)) le2 --; // Detail!! : Don't disturb the prefix !!
else ans ++;
}
printf("%d\n",ans);
return 0;
}