luoguP10505

\(luogu\)

思路

纯贪心(其实不用看的)

这是在机房,我左右两边两个巨佬提出的,水过了第 15 行后就被老师 hack 了,俩人讨论后发现贪心有局限性

01 分数规划(正解)

01 分数规划是什么?

01 分数规划多用于求解类似于给出 \(a,b\) 数组,求选择 \(k\) 个数 \(p\),使得 \(\frac{\sum_{i = 1}^{k} a_{p_i}}{\sum_{i = 1}^{n} b_{p_i}}\) 最大化。

01 分数规划怎么求?

01 分数规划多使用二分求解,下面推一下 check:

首先有

\[\frac{\sum_{i = 1}^{k} a_{p_i}}{\sum_{i = 1}^{k} b_{p_i}}> mid \]

移项得

\[\frac{\sum_{i = 1}^{k} a_{p_i}}{\sum_{i = 1}^{k} b_{p_i}}-mid>0 \]

再次移项得

\[{\sum_{i = 1}^{k} a_{p_i}}-mid\times{\sum_{i = 1}^{k} b_{p_i}}>0 \]

化简得

\[{\sum_{i = 1}^{k} a_{p_i}-mid\times b_{p_i}}>0 \]

引入本题

这就是一个 01 分数规划板子,直接分数二分套板子就好了

code

#include<bits/stdc++.h>
//#define int long long
#define esp 1e-6//精度差
using namespace std;
inline int read(){
	char c=getchar();
	int ret=0,f=1;
	while(c<'0'||c>'9'){
		if(c=='-')f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		ret=(ret<<3)+(ret<<1)+c-'0';
		c=getchar();
	}return ret*f;
}
inline void write(int x,int op){
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10,0);
	putchar((char)(x%10+'0'));
	if(op){
		if(op>0)puts("");
		if(op<0)putchar(' ');
		if(op==0)puts("114514");
	}
}
const int N=1e3+10;
int n,k;
double a[N],b[N];
bool cmp(double x,double y){return x>y;}
bool check(double x){
	double ret=0,c[N];
	for(int i=1;i<=n;i++)c[i]=a[i]-x*b[i];
	sort(c+1,c+1+n,cmp);//排序,为贪心做准备
	for(int i=1;i<=n-k;i++)ret+=c[i];//贪心的选取最大
	return ret>0;
}
int main(){
	n=read(),k=read();
	while(n||k){
		for(int i=1;i<=n;i++)a[i]=read();
		for(int i=1;i<=n;i++)b[i]=read(); 
		double l=0.0,r=114.0;//二分上下界
		while(r-l>=esp){
			double mid=(l+r)/2.0;
			if(check(mid))l=mid;
			else r=mid;
		}printf("%.0lf\n",100*l);//按题目要求输出l*100
		n=read(),k=read();
	}
	return 0;
}//*~完结撒花~*
posted @ 2024-07-24 08:23  BriskCube  阅读(34)  评论(0)    收藏  举报