[贪心]点菜

题目描述

有n个人到一家餐馆点菜。这家餐馆总共有m道菜,每一道菜都有两个属性——美味度和价格。这n个人每周都会来一次,每次只会点一道菜或不点。在这n个人中,有p个人比较挑剔,他们只能接受美味度大于等于一定值的菜;有q个人比较贫穷,他们只能点价格小于等于一定值的菜。现在请你计算:这些人至少要来几周,才可能能把餐馆的所有的菜都点过一遍?

输入格式

第1行,四个正整数n,m,p,q

第2~m+1行,每行两个数,表示菜的美味度和价格。

第m+2行p个数,表示p个挑剔的人分别能接受的菜的美味度的下限。

第m+3行q个数,表示q个贫穷的人分别能点的菜的价格的上限。

输出格式

一行一个数,即这些人最少要来的周数。若不论这些人来几周都不可能把菜点过一遍,输出-1。

输入输出样例

输入
2 3 1 1

5 2

5 3

6 4

5

1

输出

3

说明/提示

对于20%的数据,m<=20

对于40%的数据,m<=2000

对于100%的数据,p+q<=n<=50000,m<=200000

题解

二维问题常见的套路就是按一维排序,另一维用离线/数据结构维护

首先,把菜按美味度从大到小排序,挑剔的人从大到小排序。

接着,二分答案,设答案为ans

然后把菜按美味度从大到小扔到一个价格的大根堆里(扔p次,每次扔的是挑剔的人可以取的),然后挑剔的人依次取出ans个(不足则全取),上一个人没取尽的对后来的人而言美味度这一维没有区别。

剩下的再让贫穷的人贪心,判断当前答案是否可行。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<queue>
 5 using namespace std;
 6 const int N=50000+5,M=200000+5;
 7 int n,m,p,q;
 8 struct point{long long x,y,id;}a[M],b[M]; bool vis[M];
 9 long long t[N],pri[N];
10 
11 bool cmpx(point g,point h) {return g.x<h.x;}
12 bool cmpy(point g,point h) {return g.y<h.y;} 
13 priority_queue<pair<long long,int> >que;
14 inline bool check(long long tim)
15  {while(!que.empty()) que.pop();
16   memset(vis,0,sizeof(vis));
17   
18   
19   int tot=m; long long cnt=0,sol=0;
20   for(int i=p;i>0;i--)
21    {cnt=tim;
22     while(tot && a[tot].x>=t[i]) 
23      {que.push( make_pair(a[tot].y,a[tot].id) ); 
24       tot--; 
25      }
26     while(!que.empty())
27      {int x=que.top().second; vis[x]=1; que.pop();
28       cnt--; sol++; if(cnt==0) break;
29      }
30     cnt=0;  
31    }
32    tot=1,cnt=0;
33   for(int i=1;i<=q;i++)    
34    {
35     while(tot<=m && b[tot].y<=pri[i])
36      {tot++; if(vis[b[tot].id]) continue;
37       cnt++; 
38      }
39     if(cnt>=tim) cnt-=tim,sol+=tim;
40     else         sol+=cnt,cnt=0; 
41    }
42   if((n-p-q)*tim>=m-sol ) return 1;
43   return 0;
44  }
45 int main()
46  {
47  scanf("%d%d%d%d",&n,&m,&p,&q);    
48  for(int i=1;i<=m;i++)     
49   {scanf("%lld%lld",&a[i].x,&a[i].y); a[i].id=i;
50    b[i]=a[i];
51   }
52       
53  for(int i=1;i<=p;++i) scanf("%lld",&t[i]);     
54  for(int i=1;i<=q;++i) scanf("%lld",&pri[i]);         
55  
56  sort(a+1,a+m+1,cmpx); sort(b+1,b+m+1,cmpy);
57  sort(t+1,t+p+1); sort(pri+1,pri+q+1);
58  
59  int l=1,r=200000,ans=-1;    
60  while(l<=r)
61   {int mid=l+r>>1;
62    if(check(mid)) ans=mid,r=mid-1;
63    else           l=mid+1;    
64   }
65  printf("%d",ans);    
66 return 0;
67  }

 

posted @ 2019-11-12 20:40  YuXiaoze  阅读(257)  评论(0编辑  收藏  举报