首先:最大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;
}