#题目链接
http://codeforces.com/problemset/problem/939/E
#题意简述
现在有一个数列,一开始为空,有两种操作。
1.加入一个数,保证这个数比之前的数都要大
2.在这个数列中选择一个子集S,使得S中的最大元素减掉S的平均值最大,输出这个最大值
#做法
首先,每次加入一个数,有两种可能,一种是最大值不变,第二种是以当前加入的这个数为最大值。
以当前这个数为最大值,那么我们就希望平均值尽量的小,显然我们从前往后取,计算平均值,当什么时候平均值要开始变大了我们就停止。然后你发现这个平均值的函数是个开口向上的单峰函数,所以我们只要三分求出这个函数的最小值就行了,然后更新一下答案。
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<iostream>
#include<cmath>
#define LL long long
#define INF (2139062143)
#define N (500001)
using namespace std;
int Q,cnt,x,opt;
LL sum[N],a[N];
double maxans;
template <typename T> void read(T&t) {
t=0;
bool fl=true;
char p=getchar();
while (!isdigit(p)) {
if (p=='-') fl=false;
p=getchar();
}
do {
(t*=10)+=p-48;p=getchar();
}while (isdigit(p));
if (!fl) t=-t;
}
double calc(int x){
return (sum[x]+a[cnt])/(1.0*(x+1));
}
int main(){
read(Q);
while (Q--){
read(opt);
if (opt==2){
printf("%.10lf\n",maxans);
}
if (opt==1){
read(x);
a[++cnt]=x;
sum[cnt]=sum[cnt-1]+x;
int l=1,r=cnt-1;
double ans=1e9;
while (l<=r){
if (r-l<=3){
ans=calc(r);
for (int i=l;i<r;i++) ans=min(ans,calc(i));
break;
}
int mid1=l+(r-l)/3,mid2=mid1+(r-l)/3;
if (calc(mid1)>calc(mid2)) l=mid1;
else r=mid2;
}
//printf("ans %.10lf\n",ans);
maxans=max(maxans,x-ans);
}
}
return 0;
}