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;
}

  

posted @ 2018-07-11 11:32  zzd233  阅读(345)  评论(0编辑  收藏  举报