牛客欢乐赛3 C题-背包

Posted zjj0624

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客欢乐赛3 C题-背包相关的知识,希望对你有一定的参考价值。

题意
给你一个价值为V的背包,给你n个物品,每一个物品都有一个价值和体积,让你求背包装m个物品时,背包里面中位数最大的值。
思路
当m为奇数的时候,我们很容易发现,背包中的中位数最大值肯定出现在n个物品中,所以我们可以直接枚举每一个物品,然后来判断当前背包是否可以满足条件,我们可以对n个物品按价值排序,这样当我们枚举到一个物品i的时候,我们只需要选出i前面的 m 2 \\frac{m}{2} 2m个物品的最小体积和i之后的 m 2 \\frac{m}{2} 2m的物品体积最小值,然后判断是否能选i这个物品为中位数。
当m为偶数的时候,我们知道我们需要选的是两个物品的总和除2,我们可以模仿奇数的时候,先确定一个物品i,然后再从剩下的i+1~n的物品中再选一个物品,使他们的和最大.在奇数的前提下,由于我们对价值排了序,满足单调性,可以二分找到第二个数字。
代码

#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;

const int N = 1e5 + 5;
struct node {
    long long l, r;
    bool operator < (const node &s) {
        return l < s.l;
    }
}a[N];

long long sum1[N], sum2[N];
int main() {
    long long v; int n, m;
    cin >> v >> n >> m;
    for(int i = 1; i <= n; i++) {
        cin >> a[i].l >> a[i].r;
    }
    sort(a + 1, a + 1 + n);
    long long ans = -1;
    priority_queue<long long> q;
    if(m & 1) {    
        for(int i = 1; i <= n; i++) {
            sum1[i] = sum1[i - 1] + a[i].r; // 维护 m / 2 个小值的最少花费 
            q.push(a[i].r);
            if(q.size() > m / 2) {
                sum1[i] -= q.top(); q.pop();
            }
        }
        while(!q.empty()) q.pop();
        for(int i = n; i >= 1; i--) {
            sum2[i] = sum2[i + 1] + a[i].r;
            q.push(a[i].r);
            if(q.size() > m / 2) {
                sum2[i] -= q.top(); q.pop(); // 维护 m / 2 个大值的最少花费 
            } 
        }
        for(int i = m / 2 + 1; i <= n - m / 2; i++) {
            if(a[i].r + sum1[i - 1] + sum2[i + 1] <= v) {
                ans = max(ans, a[i].l);
            }
        } 
    } else {
        for(int i = 1; i <= n; i++) {
            sum1[i] = sum1[i - 1] + a[i].r;
            q.push(a[i].r);
            if(q.size() > m / 2 - 1) {
                sum1[i] -= q.top(); q.pop();
            }
        }
        while(!q.empty()) q.pop();
        for(int i = n; i >= 1; i--) {
            sum2[i] = sum2[i + 1] + a[i].r;
            q.push(a[i].r);
            if(q.size() > m / 2) {
                sum2[i] -= q.top(); q.pop();
            }
        }
        for(int i = m / 2; i <= n - m / 2; i++) {
            int left = i + 1;
            int right = n - (m / 2) + 1;
            while(left <= right) {
                int mid = left + right >> 1;
                if(sum2[mid] + sum1[i - 1] + a[i].r <= v) { 
                    left = mid + 1;
                    ans = max(ans, (a[i].l + a[mid].l) / 2);
                } else {
                    right = mid - 1;
                }
            }
        }
    }
    cout << ans << "\\n";
    return 0;
}

以上是关于牛客欢乐赛3 C题-背包的主要内容,如果未能解决你的问题,请参考以下文章

SSL新年欢乐赛暨BPM退役赛

牛客欢乐赛1 E题

牛客 | 一起来做题~欢乐赛2 (AK 题解)

牛客2021年愚人节比赛 题解

9.22“月饼杯”递归算法欢乐赛测试报告总结

牛客 2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛 签到题13题