题意
传送门 NC 17315
题解
求满足 ∑ 0 ≤ j < m b j ≤ v \sum\limits_{0\leq j<m}b_{j}\leq v 0≤j<m∑bj≤v 时物品价值的最大中位数。先讨论物品数量为奇数的情况,为了满足约束条件,使物品按价值有序,对于答案对应的物品,在背包中大于等于以及小于等于它的物品数量都至少为 m / 2 m/2 m/2;因为中位数对应的物品体积一定要计入背包,那么目标是使大于等于以及小于等于它的 m / 2 m/2 m/2 个物品总体积最小。分别向前以及向后遍历一遍,用优先队列维护物品左侧与右侧数量为 m / 2 m/2 m/2 的物品体积和的最小值。最后枚举物品,满足条件且价值最大的即答案。
物品数量为偶数的情况复杂一些,若枚举任意一对节点,复杂度达到 O ( n 2 ) O(n^2) O(n2),显然是不行的。观察到按价值单调不减的物品,其右侧(或左侧)的某个固定数量的体积和单调不增,那么可以枚举中间两个物品的其中一个,二分求另外一个。
#include <bits/stdc++.h>
using namespace std;
#define maxn 100005
struct node
{
int a, b, ls, rs;
bool operator<(const node &nd) const
{
return a < nd.a;
}
} ns[maxn];
int v, n, m;
int main()
{
scanf("%d%d%d", &v, &n, &m);
for (int i = 0; i < n; i++)
{
scanf("%d%d", &ns[i].a, &ns[i].b);
}
sort(ns, ns + n);
priority_queue<int> q;
int f = m & 1, limit = m / 2, sum = 0;
for (int i = 0; i < n; i++)
{
int v = ns[i].b;
q.push(v);
ns[i].ls = sum, sum += v;
if (q.size() > limit - 1 + f)
{
sum -= q.top();
q.pop();
}
}
while (!q.empty())
q.pop();
sum = 0;
for (int i = n - 1; i > 0; i--)
{
int v = ns[i].b;
q.push(v);
ns[i].rs = sum, sum += v;
if (q.size() > limit)
{
sum -= q.top();
q.pop();
}
}
int res = -1;
if (f)
{
for (int i = limit; i < n - limit; i++)
{
if (ns[i].b + ns[i].ls + ns[i].rs <= v)
{
res = max(res, ns[i].a);
}
}
}
else
{
for (int i = limit - 1; i < n - limit; i++)
{
int lb = i, ub = n - limit;
while (ub - lb > 1)
{
int mid = (lb + ub) >> 1;
if (ns[i].ls + ns[i].b + ns[mid].rs <= v)
lb = mid;
else
ub = mid;
}
if (ns[i].ls + ns[i].b + ns[ub - 1].rs <= v)
res = max(res, ns[i].a + ns[ub].a);
}
}
printf("%d\n", f ? res : res / 2);
}