牛客欢乐赛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题-背包的主要内容,如果未能解决你的问题,请参考以下文章