题意
维护一个集合,两种操作:
1、向集合加入一个数,保证这个数比集合中所有数都大
2、在集合中找一个子集,使子集中最大值减平均值最大,输出这个最大值
解题思路
加入第
i
i
i个数
A
i
Ai
Ai后,考虑包含
A
i
Ai
Ai的子集对
a
n
s
ans
ans的影响。
因为所选子集中最大值已经确定为
A
i
Ai
Ai,只需尽可能减小子集中的平均值。
由贪心的思想,一定尽可能选较小的数,即选取的一定为序列
A
A
A的一个前缀,于是暴力方法就是枚举前缀结束位置
j
j
j。
由平均数性质,向后枚举时如果新加入的
A
j
Aj
Aj小于之前已经加入的数的平均值,则一定拉低平均值,反之会抬高平均值。
由于
A
A
A递增,显然所得平均值是单峰的,这样就可以使用三分。
代码
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
using namespace std;
long long sum[500005];
double ans;
int q,x,num;
inline double check(int w){
return 1.0*(sum[w]+x)/(w+1);
}
int main(){
int opt;
scanf("%d",&q);
while(q--){
scanf("%d",&opt);
if(opt==2) {printf("%.8lf\n",ans);continue;}
scanf("%d",&x);
int l=1,r=num;
while(l<r){
int mid=l+r>>1;
int midd=mid+r>>1;
if(mid==midd) midd++;
double r1=check(mid),r2=check(midd);
if(r1>r2) l=mid+1;
else r=midd-1;
}
if(l==r) ans=max(ans,1.0*x-1.0*(sum[l]+x)/(l+1));
sum[++num]=x;sum[num]+=sum[num-1];
}
return 0;
}