首先:最大Vz/Wz不是说按照单个Vz/Wz排序,这可是除法口牙!用样例看看就明白了
修补骑士一开始感觉这是个01背包,但是这里使用太复杂了,可能会吃MLE或者TLE,后面自我寻思了一下发现了:
能达到的单位价值。所以说是bz/az >= m,找到这个最大的m(保留两位小数) 二分关系在于:无论对于哪一种ab选择情况,m对于>0都一定是负贡献
就像是一堆一次函数,m上升(相当于x),符合要求的选择方式肯定会越变越少 我们需要的就是:最后一个存活>0的,他最接近于等于0时对应的m
对于每一个可能的m,我们计算所有b - a*m(这个是线性的,可以相加),之后加在一起看是否大于0,如果大于,就是二分当中的可能情况,反之同理
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,k;
int w[100009];
int v[100009];
bool check(double m,int k)
{
double tout[n];
for(int y = 0;y < n;y++)
{
tout[y] = v[y] - w[y] * m;
}
sort(tout,tout + n);//默认升序
reverse(tout,tout + n);
double theaim = 0;
for(int y = 0;y < k;y++)
{
theaim += tout[y];
}
if(theaim >= 0)
{
return 1;
}
else
{
return 0;
}
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T;
cin >> T;
for(int t = 0;t < T;t++)
{
cin>>n>>k;
memset(w,0,n);
memset(v,0,n);//这个可能出现段错误的地方果然又忘了
for(int r = 0;r < n;r++)
{
cin>>w[r]>>v[r];
}
double left = 0;
double right = 1000000.0;
while(right - left >= 0.001)
{
double mid = (left + right)/2;
if(check(mid,k))
{
left = mid;
}
else
{
right = mid;
}
}
printf("%.2lf\n",left);
}
return 0;
}