Codeforces Gym100187C Very Spacious Office 贪心 堆

原文链接https://www.cnblogs.com/zhouzhendong/p/CF-Gym100187C.html

题目传送门 - CF-Gym100187C

题意

  给定 $n$ 个房间以及 $n$ 个人。

  第 $i$ 个房间的大小为 $a_i$。

  第 $i$ 个人要的房间的大小范围为 $[L_i,R_i]$ 。

  现在给每一个人安排房间,一个房间只能被一个人拥有。

  问是否存在方案满足条件。

  如果不存在,输出:Let's search for another office.

  如果存在多种方案,输出:Ask Shiftman for help.

  否则输出:Perfect! 并在第二行输出 $n$ 个数,第 $i$ 个数表示给第 $i$ 个人分配的房间编号。

题解

  首先我们不考虑多种解的情况。

  做法是个简单贪心。

  我们将房间按照 $a_i$ 升序排序。

  将人的需求按照 $L_i$ 升序排序。

  然后从左到右依次处理每一个房间。

  对于房间 $i$ ,我们从 $L$ 比他小的所有还没有被匹配的人中找到 $R_j$ 最小的(这个可以用一个堆来实现)。

  如果 $R_j<a_i$ 那么由于未匹配的房间中最小的就是 $a_i$,所以这个人一定无法匹配了,所以无解。

  否则让房间 $i$ 匹配第 $j$ 个人。显然让 $R_i$ 尽量小的先匹配时最优的。

  这样可以得到一组解。

  然后我们考虑如何判断是否多解。

  假设我们已经有了一个解。

  则,当且仅当下面的条件满足时,存在多解。

  条件: 存在两个人,选择的房间都在他们两个人都可以接受的范围内。

  于是我们要考虑如何来搞这个。

  考虑对于当前人选择的当前房间。我们找到满足“选择的房间比当前房间小的,可以接受的区间比当前房间大的”人中选择的房间尽量大的,判断这两个人的房间是否可以交换。如果有解,并至少存在一组这样的人,那么为多解。这个东西显然可以再用个堆搞定。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=100005;
int n,a[N],b[N];
struct Node{
int a,id;
}v[N];
struct Seg{
int L,R,id;
Seg(){}
Seg(int _L,int _R){L=_L,R=_R;}
friend bool operator < (Seg a,Seg b){
return a.R>b.R;
}
}s[N];
int res[N];
bool cmpL(Seg a,Seg b){return a.L<b.L;}
bool cmpid(Seg a,Seg b){return a.id<b.id;}
bool cmpa(Node a,Node b){return a.a<b.a;}
priority_queue <Seg> Q,Q2;
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&v[i].a),v[i].id=i;
sort(v+1,v+n+1,cmpa);
v[0].a=0,v[n+1].a=1e9+1;
for (int i=0;i<=n+1;i++)
a[i]=v[i].a,b[n+1-i]=1e9+1-v[i].a;
for (int i=1;i<=n;i++){
scanf("%d%d",&s[i].L,&s[i].R);
s[i].id=i;
s[i].L=lower_bound(a,a+n+2,s[i].L)-a;
s[i].R=n+1-(lower_bound(b,b+n+2,1e9+1-s[i].R)-b);
// printf("%d %d\n",s[i].L,s[i].R);
}
while (!Q.empty())
Q.pop();
while (!Q2.empty())
Q2.pop();
sort(s+1,s+n+1,cmpL);
bool flag=0;
for (int i=1,j=1;i<=n;i++){
while (j<=n&&s[j].L<=i)
Q.push(s[j++]);
if (Q.empty()){
puts("Let's search for another office.");
return 0;
}
Seg now=Q.top();
Q.pop();
if (now.R<i){
puts("Let's search for another office.");
return 0;
}
res[now.id]=v[i].id;
while (!Q2.empty()){
Seg Now=Q2.top();
if (Now.L<i){
Q2.pop();
continue;
}
if (now.L<=n-Now.R)
flag=1;
break;
}
Q2.push(Seg(now.R,n-i));
}
if (flag){
puts("Ask Shiftman for help.");
return 0;
}
puts("Perfect!");
for (int i=1;i<=n;i++)
printf("%d ",res[i]);
return 0;
}

  

上一篇:jquery on()


下一篇:Subsets