前言
听说教主有一次在 ACM 里面速A了一题最优比率生成树问题,然而后面许多人跟风失败….算了还是好好学习,天天向上, Orz 教主吧。
题意
给你n对数 a[i],b[i] ,让你取m对,使得 ∑a[i]∑b[i] 最大。
数据范围
对于100%的数据,2≤K≤N≤100000,1≤a,b≤1000
分析
数学分析中一个很重要的方法就是分析目标式,这样我们来看目标式。
R=∑(a[i]∗x[i])/∑(b[i]∗x[i])
这时可以设一个函数
f(L)=∑a[i]∗x[i]−∑b[i]∗x[i]∗L
让这个式子尽量接近原式
R
。
那么这时可以设
移项
∑a[i]∗x[i]>∑b[i]∗x[i]∗L
再转成
(∑a[i]∗x[i])/(∑b[i]∗x[i])
的形式:
(∑a[i]∗x[i])/(∑b[i]∗x[i])>L
这时很明显L越大,则答案
(∑a[i]∗x[i])/(∑b[i]∗x[i])
越大。(注意要保证
f(l)>0
)
这就是二分法了,去二分L,再去验证
f(L)
是否大于
0
,且这时的方案
模型:
二分法
L:=…;R:=…;
Repeat
Mid:=(L+R)/2;
For I=1..X do D[i]:=A[i]-Mid*B[i];//根据Mid计算D数组
if 检查(Mid)成功 then L:=Mid else R:=Mid;
Until abs(L-R)
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=100005;
int i,n,m,a[N],b[N];
double d[N],an,l,r,mid;
int main(){
scanf("%d %d",&n,&m);
fo(i,1,n) scanf("%d",&a[i]);
fo(i,1,n) {scanf("%d",&b[i]);}
l=1;r=N;
while (r-l>0.00001) {
mid=(l+r)/2*1.0;
fo(i,1,n) d[i]=a[i]-mid*b[i];
sort(d+1,d+n+1);an=0;
fd(i,n,n-m+1) an=an+d[i];
if (an>0) l=mid; else r=mid;
}
printf("%.3lf",(l+r)/2*1.0);
}