zoukankan      html  css  js  c++  java
  • 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
    ",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;
    }
    

      

  • 相关阅读:
    POJ 1789:Truck History
    POJ 1258:Agri-Net Prim最小生成树模板题
    POJ 1837:Balance 天平DP。。。
    杭电1754--I Hate It(线段树)
    Poj3259--Wormholes(Spfa 判负环)
    杭电1068--Girls and Boys(二分图最大独立集)
    杭电1010--Tempter of the Bone(Dfs+剪枝)
    杭电2647--Reward(反向拓扑)
    杭电1083--Courses(二分图匹配)
    杭电2063--过山车(二分匹配)
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/CF-Gym100187C.html
Copyright © 2011-2022 走看看