Wannafly挑战赛20-B-背包(优先队列+二分)

链接:https://www.nowcoder.com/acm/contest/133/B
来源:牛客网
 

题目描述

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

输入描述:

第一行三个数v, n, m,分别代表背包容量,物品数量以及需要取出的物品数量

接下来n行,每行两个数ai,bi,分别代表物品价值以及大小

n ≤ 1e5, 1 ≤ m ≤ n, ai ≤ 1e9, v ≤ 1e9, bi ≤ v

输出描述:

仅一行,代表最大的中位数

示例1

输入

复制

20 5 3
3 5
5 6
8 7
10 6
15 10

输出

复制

8

题解:

对于偶数,我是暴力中间靠左边的数,,直接二分查找右端即可。

#include<queue>
#include<stdio.h>
#include<algorithm>
using namespace std;
#define ll long long
int n,m,v;
ll sum[100005],sum1[100005],ans,dp[100005];
priority_queue<int>q,q1,qq;
struct node
{
    int w,v,id;
}a[100005];
bool comp(node a,node b)
{
    if(a.v==b.v)
        return a.w<b.w;
    return a.v<b.v;
}      
int main(void)
{
    scanf("%d%d%d",&v,&n,&m);    
    for(int i=1;i<=n;i++)
        scanf("%d%d",&a[i].v,&a[i].w);
    sort(a+1,a+n+1,comp);
    for(int i=1;i<=(m-1)/2;i++)
            q.push(a[i].w),sum[(m-1)/2]+=a[i].w;
    for(int i=(m-1)/2+1;i<=n;i++)
    {
        sum[i]=sum[i-1];
        if(a[i].w>q.top())
            continue;
        sum[i]-=q.top();q.pop();
        q.push(a[i].w);sum[i]+=a[i].w;
    }
    for(int i=n;i>n-(m-1)/2;i--)
        q1.push(a[i].w),sum1[n-(m-1)/2+1]+=a[i].w;
    for(int i=n-(m-1)/2;i>0;i--)
    {     
        sum1[i]=sum1[i+1];
        if(a[i].w>q1.top())
            continue;
        sum1[i]-=q1.top();q1.pop();
        q1.push(a[i].w);sum1[i]+=a[i].w;
    }
    if(m%2)
    {
        for(int i=(m-1)/2+1;i<=n-(m-1)/2;i++)
            if(sum[i-1]+sum1[i+1]+a[i].w<=v)
                ans=max(ans,(ll)a[i].v);
        printf("%lld\n",ans);
    }
    else
    {
        for(int i=(m-1)/2+1;i<=n-(m-1)/2-1;i++)
		{
			int l=i+1,r=n-(m-1)/2,mid,p=-1;
			while(l<=r)
			{
				mid=(l+r)/2;
				if(sum[i-1]+sum1[mid+1]+a[i].w+a[mid].w<=v)
					p=mid,l=mid+1;
				else
					r=mid-1;
			}
			if(p>0) ans=max(ans,(ll)(a[i].v+a[p].v));
		}
        printf("%lld\n",ans/2);
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值