题目链接
题意
Applese有1个容量为v的背包,有n个物品,每一个物品有一个价值ai,以及一个大小bi
然后他对此提出了自己的疑问,如果我不要装的物品装的价值最大,只是一定需要装m个物品,要使得求出来的物品价值的中位数最大
Applese觉得这个题依然太菜,于是他把这个问题丢给了你
当物品数量为偶数时,中位数即中间两个物品的价值的平均值
思路
- 先将物品按价值小到大排序
- 若选择物品为奇数个,则中位数左边和右边各选m/2个即可,若选多了把体积大的删去
- 若选择物品为偶数个,则中位数由中间两位决定,左边选m/2-1个,右边选m/2个,为了使中位数更大,由于物品已排序,可以让右边选的物品区间尽可能靠右,使用二分确定位置
参考代码
#include<bits/stdc++.h>
using namespace std;
struct node
{
long long a,b;
};
node aa[1001000];
long long sum1[1000100],sum2[1000100];
int cmp(node a, node b)
{
return a.a<b.a;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
long long v,n,m;
cin>>v>>n>>m;
long long x=0,ans=0;
if(m%2!=0)
x=1;
for(int i=1; i<=n; i++)
{
cin>>aa[i].a>>aa[i].b;
}
sort(aa+1,aa+n+1,cmp);
priority_queue<long long> q;
for(int i=1; i<=n; i++)
{
q.push(aa[i].b);
sum1[i]=sum1[i-1]+aa[i].b;
if(q.size()>m/2-1+x)
{
sum1[i]-=q.top();
q.pop();
}
}
while(!q.empty())
q.pop();
for(int i=n; i>=1; i--)
{
q.push(aa[i].b);
sum2[i]=sum2[i+1]+aa[i].b;
if(q.size()>m/2)
{
sum2[i]-=q.top();
q.pop();
}
}
if(x)
{
for(int i=m/2+1; i<=n-m/2; i++)
{
if(sum1[i-1]+sum2[i+1]+aa[i].b<=v)
{
ans=aa[i].a;
}
}
cout<<ans<<endl;
}
else
{
for(int i=m/2; i<=n-m/2; i++)
{
int l=i+1,r=n-m/2+1;
while(l<=r)
{
int mid=(l+r)/2;
if(aa[i].b+sum1[i-1]+sum2[mid]<=v)
{
l=mid+1;
}
else
{
r=mid-1;
}
}
if(r>i)
ans=max(ans,(aa[i].a+aa[r].a)/2);
}
cout<<ans<<endl;
}
}