题意:
有n个物品,每个物品有两个属性a,b
第一个人选p个物品,第二个人从第一个人选的p个物品中选k个物品
第二个人选的顺序是,先选b比较小的,相同b之间选a比较小的
第一个人想让第二个人选出物品的a总和最大,其次总和a相同的情况下:
第二个人没有选的p-k个物品的b总和最大
问第一个人应该选出那p个物品
思路:
稍微绕一点的二维贪心问题。
先按第二个的挑选顺序进行排序 :数组 A
在按 第一关键词 a 从大到小 , 第二关键词 第二个人的挑选顺序从小到大 进行间接排序 :数组pos
这样如果拿pos数组的前k个就能使得就能使得拿出的a总和最大
然后我们还需要拿p-k个物品,要求当把他们和拿出的k个物品一起拿给第二个人时,第二人不会选这p-k个。
那么很明显,这p-k个在 (第二个人中的挑选顺序)一定大于拿出的k个物品
维护记录拿出的k个物品中最大的(第二个人中的挑选顺序)的优先队列
每次判断是否还存在比 最大挑选顺序 大p-k个的元素
如果存在了,那么下一步的任务是使没有选的p-k个物品的b属性最大
很明显,只需要对比 最大挑选顺序 还要大 的元素按b属性从大到小进行排序
然后选择最大的p-k个就是答案了
代码:
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
int n,p,k;
struct node{
int a,b,id;
}A[100005];
int pos[100005];
priority_queue< int >Q;
priority_queue< pii >Q1;
bool cmp(node a,node b){
if(a.b!=b.b)return a.b>b.b;
return a.a<b.a;
}
bool cmp2(int a , int b){
if(A[a].a!=A[b].a)return A[a].a>A[b].a;
return a<b;
}
bool cho[100005];
int main()
{
scanf("%d%d%d",&n,&p,&k);
for(int i=0;i<n;i++){
scanf("%d%d",&A[i].a,&A[i].b);
A[i].id = i + 1;
pos[i] = i;
}sort(A,A+n,cmp);
sort(pos,pos+n,cmp2);
for(int i=0;i<k;i++){
Q.push(pos[i]);
cho[A[pos[i]].id] = true;
}int index = k;
p-=k;
while(1){
int t = Q.top();
if(t+p<n){
while(++t<n){
Q1.push(pii(A[t].b,t));
}break;
}Q.pop();
cho[A[t].id] = false;
cho[A[pos[index]].id] = true;
Q.push(pos[index++]);
}while(p--){
pii t = Q1.top();
Q1.pop();
cho[A[t.se].id] = true;
}for(int i=1;i<=n;i++)if(cho[i])
printf("%d ",i);
return 0;
}