[模板]最大化平均值

[模板]最大化平均值

给出(n)个物品的体积和价值,取(k)个物品,使得价值与体积之比最大

考虑二分答案,check(x)表示检查是否存在一个大小为(k)的子集使得集合中物品的价值与体积之比(>=x)

即$ frac{sum v_i}{sum w_i} geq x$

移项得 (sum v_i geq sum w_i · x)

(sum (v_i-w_i · x) geq 0)

可以贪心地取前(k)大的(v_i-w_i · x)值,若总值$ geq 0$就满足条件,否则不满足条件

取前(k)大值可以用(nth\_element) (O(n))实现

(mathcal{std}):

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=100010;
inline int read(){
	int x=0; char c=getchar();
	while(c<'0') c=getchar();
	while(c>='0') x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x;
}
int n,k,v[N],w[N];
double p[N];
inline bool check(double x){
	for(int i=1;i<=n;++i)
		p[i]=double(v[i])-x*double(w[i]);
	nth_element(p+1,p+1+n-k,p+1+n);
	double sum=0;
	for(int i=n;i>=n-k+1;--i)
		sum+=p[i];
	return sum>=0;
}
int main()
{
	n=read(),k=read();
	for(int i=1;i<=n;++i)
		w[i]=read(),v[i]=read();
	double l=0,r=1e12;
	while(r-l>1e-7){
		double mid=(l+r)/2.0;
		if(check(mid)) l=mid;
		else r=mid;
	}
	printf("%.5lf
",l);
	fclose(stdin); fclose(stdout);
	return 0;
}
原文地址:https://www.cnblogs.com/yjkhhh/p/9885259.html