[贪心]点菜
题目描述
有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 }