P4110 [HEOI2015]小L的白日梦
截止本文提交(2022.4.2)前,洛谷题解区的三篇博客证明均为错误的,希望管理员看到后撤掉。
因为期望的线性性,答案即为
题意可以理解为,给
引理 1:选出的
这里需要注意的是,网传的对于降序数组交换两个数后证明答案变大的证法是绝对错误的,这只能证明降序数组要优于降序数组交换两个数的答案,不能证明降序数组比其他所有情况更优,属于是学 exchange argument 没学会还乱用了。
假设我们已经选定
假设
由排序不等式得
引理 2:选出的
我们设选择的数下标按顺序为
若
若
所以一定会选择一段前缀和一段后缀。
假设至少存在一个数不属于前缀或后缀。
不失一般性地,我们设选择的前缀为
考虑将
考虑将
接下来只需证明
显然有
若
若
在知道这两个性质后这道题就可以做了,
#include<cstdio>
#include<algorithm>
#include<functional>
#include<utility>
void solve(){
int n,k;
scanf("%d %d",&n,&k);
std::pair<long double,int> p[100010];
for(int i=1,x,y;i<=n;i++){
scanf("%d/%d %d",&x,&y,&p[i].second),p[i].first=1.*x/y;
if(!p[i].second) --n,--i;
}
std::sort(p+1,p+n+1,std::greater());
if(k==1) return puts("0.000000"),void();
long double pl=p[1].first,pr=p[n].first;
int l=1,r=n;
k-=2,p[1].second--,p[n].second--;
long double ans=0;
while(k){
while(!p[l].second) ++l;
while(!p[r].second) --r;
int x;
if(pl+pr>=1){
if(p[l].first==pl) x=std::min(k,p[l].second);
else x=1;
k-=x,p[l].second-=x;
ans+=(1-pl)*p[l].first+(x-1)*(1-p[l].first)*p[l].first;
pl=p[l].first;
}else{
if(p[r].first==pr) x=std::min(k,p[r].second);
else x=1;
k-=x,p[r].second-=x;
ans+=(1-p[r].first)*pr+(x-1)*(1-p[r].first)*p[r].first;
pr=p[r].first;
}
}
ans+=(1-pl)*pr;
printf("%.6Lf\n",ans);
}
int main(){
int T;
scanf("%d",&T);
while(T--) solve();
return 0;
}