题目描述
海盗头子普朗克在珍宝岛上找到一批宝物,宝物有 n n n 件,第 i i i 件宝物的价值为 c i c_i ci,重量为 w i w_i wi。普朗克想取其中的 k k k 件宝物,使得这些宝物的价值之和除以重量之和(实数除法)达到最大。请帮他求出这个最大值。
输入格式
第一行两个正整数
n
,
k
n, k
n,k。
接下来
n
n
n 行,每行两个正整数
c
i
,
w
i
c_i,w_i
ci,wi。
输出格式
一个数,即你所求出的最大值,保留四位小数。
输入样例
3 2
7 2
11 6
5 3
输出样例
2.4000
样例解释
选择第一个和第三个宝物,价值之和除以重量之和 ( 7 + 5 ) ÷ ( 2 + 3 ) = 2.4 (7+5) \div (2+3)=2.4 (7+5)÷(2+3)=2.4,达到最大。
输入样例2
6 3
18 96
22 41
34 14
7 87
27 47
79 12
输出样例2
2.0149
数据范围
对于 100 % 100\% 100% 的数据, 1 ≤ n , c i , w i ≤ 1 0 5 1 \leq n, c_i, w_i \leq 10^5 1≤n,ci,wi≤105,保证答案不超过 1 0 9 10^9 109。
题目解答
这竟然是一道二分答案题,作为蒟蒻的我第一次做时竟然没有看出来。首先我们应该想如何写每次二分时的 check
函数:
- 假设我们当前二分枚举到的值为
ans
\text{ans}
ans,选的
k
k
k 个物品价值之和为
∑
c
i
\sum c_i
∑ci,重量之和为
∑
w
i
\sum w_i
∑wi,那么求如下式子的真假即可:
∑ c i ∑ w i ≥ ans \dfrac{\sum c_i}{\sum w_i} \geq \text{ans} ∑wi∑ci≥ans - 不妨对它进行变换:
∑ c i ∑ w i ≥ ans = ∑ c i ≥ ans × ∑ w i = ∑ c i − ∑ ( ans × w i ) ≥ 0 = ∑ ( c i − ans × w i ) ≥ 0 \begin{aligned} & \dfrac{\sum c_i}{\sum w_i} \geq \text{ans} \\ = & \sum c_i \geq \text{ans} \times \sum w_i \\ = & \sum c_i - \sum (\text{ans} \times w_i) \geq 0 \\ = & \sum (c_i - \text{ans} \times w_i) \geq 0 \end{aligned} ===∑wi∑ci≥ans∑ci≥ans×∑wi∑ci−∑(ans×wi)≥0∑(ci−ans×wi)≥0 - 只要我们每次将 c i − ans × w i c_i - \text{ans} \times w_i ci−ans×wi 的值降序排序,取前 k k k 个元素,看它们的和是不是大于 0 0 0 即可,时间复杂度 O ( n log n log ( ∑ w i ) ) O(n \log n \log ( \sum w_i) ) O(nlognlog(∑wi))。代码如下:
AC代码
#include <bits/stdc++.h>
using namespace std;
int n, k, c[100005], w[100005];
double l, r, arr[100005];
bool check(double x)
{
double res = 0;
for (int i = 1; i <= n; i++)
arr[i] = c[i] - w[i] * x; // 计算ci - wi * x
sort(arr + 1, arr + n + 1, greater<double>()); // 降序排序
for (int i = 1; i <= k; i++) // 累加前k个数
res += arr[i];
return res >= 0;
}
int main()
{
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; i++)
{
scanf("%d %d", c + i, w + i);
r += c[i];
}
while (r - l > 1e-6) // 二分答案
{
double mid = (l + r) / 2.0;
if (check(mid))
l = mid;
else
r = mid;
}
printf("%.4lf", l);
return 0;
}
好了,本期博客就到这里,若注解有误,还请各位大佬多多指教。
另外,觉得写得好的话,还可以点赞+收藏哦
^
⌣
^
\hat{} \smile \hat{}
^⌣^