题目背景
Facer 误闯入禁地,学会了魔法。
题目描述
Facer 闯入禁地之后,遇到了对手。
具体来说,Facer 魔法是一串数字。
但是 Facer 能力有限,这串数字只能从给定的 n 个数中选择,能产生的魔法值为选择出的这些数字的平均数。
他的对手不会像 Facer 这样的强大的魔法,但是他会克制招数,即从 Facer 选出的数字中找出中位数,便是他的魔法值。
求 Facer 最多能克制对方多少点魔法。
一句话题意:给你 n 个数,你可以选若干个数,使得平均数减中位数最大。
输入格式
第一行一个正整数 n。
第二行 n 个数如题。
输出格式
Facer 能克制对方多少魔法值,精确到两位小数。
首先我们阔以证明一个结论,选择奇数个一定比选择偶数个更优,比如你选了偶数个,我们把中间两个较大的数去掉,对平均数的影响必然更小(阔以证明),之后呢由于这题的数据范围决定了这个应该是个nlog的算法,所以我们阔以枚举中位数,之后用三分求最大值(因为这个题满足单峰函数的性质。
水题
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int n;
int a[100005];
int sum[100005];
double ans;
double max_1(double x,double y){
return x>y?x:y;}
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void solve(int tmp){
//单峰函数,三分算法天下第一
int zhongwei=a[tmp];
int l=1,r=min(tmp-1,n-tmp);
int mid,midr;
int maxx1,maxx2;
double anss=0;
while(r>l){
mid=(l*2+r)/3;
midr=(l+r*2+2)/3;
maxx1=sum[n]-sum[n-mid]+sum[tmp]-sum[tmp-mid-1];
maxx2=sum[n]-sum[n-midr]+sum[tmp]-sum[tmp-midr-1];
if(maxx1*(2*midr+1)<maxx2*(2*mid+1)) l=mid+1;
else r=midr-1;
}
anss=(double)1.0*(sum[n]-sum[n-l]+sum[tmp]-sum[tmp-l-1])/(l*2+1);
ans=max_1(ans,anss-(double)(1.0)*zhongwei);
}
int main(){
n=read();
sum[0]=0;
for(int i=1;i<=n;i++) a[i]=read();
sort(a+1,a+n+1);//排序么么哒
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
for(int i=2;i<=n-1;i++)solve(i);//枚举中位数 选择奇数个数字
printf("%.2lf",ans);
return 0;
}