牛客多校第四场A gpa (01分数规划)

多校是越打越自闭了。。。

这个题就是给你一个数列a和一个数列b,然后让你从这两个数列中中最多删除k个项(注意是同时删除a[i]和b[i]),问你剩下来的sigma(a[i]*b[i])/sigma(a[i])最大值。然后比赛的时候我根本没做过这种经典问题(听说白书上是有的),我就用了一个贪心的做法,出了几个数据好像是没有问题的,但是这个贪心根本就证明不了,然后比赛交题的时候过的case数居然是0。

比赛结束后看了题解,大概就是一个板子题吧。

这个题它的做法就是二分答案。先来看一个式子。

我们要求的目标式就是左边这个东西。对于一个答案D,如果我们能找到更优解,那么一定满足这个不等式,把不等式变形。然后就发现是可以二分这个D的,题目里也给出了这个c[i]的范围。我们就找让这个不等式成立的最大的D。就把这个是s[i](c[i]-D)排个序,至多删除k项,就把就k小的项都删除,判断剩下来的项的和,把和与0比较进行二分D。
这个复杂度是NlogN。这么写就过了,标程的话还对排序优化了一下,用了nth_element()这个函数,可以了解一下。

#include<iostream>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<cmath>
using namespace std;

typedef long long ll;
typedef long double ld;
const double eps=1e-6;

struct node
{
    double s,c;
} p[100005];
double d[100005];


int main()
{
    int n,k;
    cin>>n>>k;
    for(int i=0; i<n; i++)
    {
        cin>>p[i].s;
    }
    for(int i=0;i<n;i++)
    {
        cin>>p[i].c;
    }
    memset(d,0,sizeof(d));

    double r=1000;
    double l=0;
    double mid;
    while(r-l>eps)
    {
        double sum=0;
        mid=(r+l)/2;
        for(int i=0; i<n; i++)
            d[i]=p[i].s*p[i].c-p[i].s*mid;
        sort(d,d+n);
        for(int i=k; i<n; i++)
            sum+=d[i];
        if(sum>=0) l=mid;
        else  r=mid;
    }
    cout<<fixed<<setprecision(7)<<l<<endl;

}

猜你喜欢

转载自blog.csdn.net/zero___zero/article/details/81369195