多校是越打越自闭了。。。
这个题就是给你一个数列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;
}