原文链接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 ",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; }