最大的中位数


Applese有1个容量为v的背包,有n个物品,每一个物品有一个价值ai,以及一个大小bi
然后他对此提出了自己的疑问,如果我不要装的物品装的价值最大,只是一定需要装m个物品,要使得求出来的物品价值的中位数最大
Applese觉得这个题依然太菜,于是他把这个问题丢给了你
当物品数量为偶数时,中位数即中间两个物品的价值的平均值

链接:https://ac.nowcoder.com/acm/problem/17315

输入描述:

第一行三个数v, n, m,分别代表背包容量,物品
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
PII a[100005];
int v,n,m; 
int l[100005];
int r[100005];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>v>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].first>>a[i].second;
    }
    sort(a,a+n);//按价值从小到大排序
    int temp1,temp2;
    if(m&1)//如果装入奇数个物品,左右个数相同,例如5个,左边就2个,右边两个,我们只需要枚举中间那一个即可
    {
        temp1=m>>1;
        temp2=m>>1;
    }
    else//8个,我们左边3个,右边4个,中间1个,进行类似三分
    {
        temp1=m/2-1;
        temp2=m/2;
    } 
    priority_queue<int> p1;//左边 
    priority_queue<int> p2;//右边
    int sum=0;
    for(int i=1;i<=n;i++)l[i]表示包括i在内前面temp1个物品的最小空间,因为我们必须尽可能留更多的空间给中间的那个
    {
        p1.push(a[i].second);
        l[i]=l[i-1]+a[i].second;
        if(p1.size()>temp1) l[i]-=p1.top(),p1.pop();
    } 
    for(int i=n;i;i--)//r[i]表示包括i在内后面temp2个物品的最小空间,因为我们必须尽可能留更多的空间给中间的那个
    {
        p2.push(a[i].second);
        r[i]=r[i+1]+a[i].second;
        if(p2.size()>temp2) r[i]-=p2.top(),p2.pop();
    }
    if(m&1)
    {
        int ans=0;
        for(int i=temp1+1;i<=n-temp2;i++)//奇数的时候我们只需要枚举中间那个的位置即可
        {
            if(l[i-1]+r[i+1]+a[i].second<=v) ans=a[i].first;
        }
        cout<<ans<<"\n";
    }
    else//否则我们需要枚举后面那部分的位置,用二分,在满足的条件下尽量往右靠,因为这个是按照价值从小到大排序的
    {
        int ans=0;
        for(int i=temp1+1;i<=n-temp2;i++)
        {
            int pos=0;
            int ln=i+1,rn=n-temp2+1;
            while(ln<=rn)
            {
                int mid=(ln+rn)>>1;
                if(l[i-1]+a[i].second+r[mid]<=v) pos=mid,ln=mid+1;
                else rn=mid-1;
            }
            if(pos) ans=max(ans,a[i].first+a[pos].first);
        }
        cout<<ans/2<<endl; 
        
    }
    
    
} 

 

   

 

也是第一次遇到这种题目,看大佬思想都用优先队列然后二分求,记住吧。

 

posted @ 2020-06-10 19:54  ___Charles  阅读(279)  评论(0)    收藏  举报