題意
維護一個集合,兩種操作:
1、向集合加入一個數,保證這個數比集合中所有數都大
2、在集合中找一個子集,使子集中最大值減平均值最大,輸出這個最大值
解題思路
加入第個數後,考慮包含的子集對的影響。
因爲所選子集中最大值已經確定爲,只需儘可能減小子集中的平均值。
由貪心的思想,一定儘可能選較小的數,即選取的一定爲序列的一個前綴,於是暴力方法就是枚舉前綴結束位置。
由平均數性質,向後枚舉時如果新加入的小於之前已經加入的數的平均值,則一定拉低平均值,反之會擡高平均值。
由於遞增,顯然所得平均值是單峯的,這樣就可以使用三分。
代碼
#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;
}