题目
题意概要
维护一个集合
S
S
S ,支持两种操作:
- 加入一个比已有的元素都大的数字。
- 对于所有的 S ′ ( S ′ ⫅ S ) S'(S'\subseteqq S) S′(S′⫅S) ,求 max ( S ′ ) − average ( S ′ ) \max(S')-\text{average}(S') max(S′)−average(S′) 的最大值。
(这里的 average \text{average} average 是求平均数的意思啦; max \max max 就不解释了)
数据范围与约定
操作数量为
1
0
5
10^5
105 ,加入的数字
x
∈
[
1
,
1
0
9
]
x\in[1,10^9]
x∈[1,109] 。
思路
感谢@weixin_30650859 的博客提供了思路。
由于最大值只有 n n n 个,考虑枚举最大值之后最小化平均数。
枚举太慢了。我们每次都会插入最大的数字,只需要考虑以它作为最大值,更新答案即可。
显然,拉低平均值,应该从最小的数字选起。可以用三分。或者是,利用一种 内在联系。
此时,那些用来拉低平均数的“小弟”,只会比上一个最大值多,不会更少。证明略。
代码
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
inline int readint(){
int a = 0; char c = getchar(), f = 1;
for(; c<'0' or c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c and c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
inline void writeint(long long x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) writeint(x/10);
putchar((x%10)^48);
}
# define MB template < class T >
MB void getMax(T &a,const T &b){ if(a < b) a = b; }
MB void getMin(T &a,const T &b){ if(b < a) a = b; }
const int MaxN = 500005;
long long s[MaxN];
int main(){
double average = 1e10, ans = 0;
for(int T=readint(),i=0,bro=0; T; --T){
int opt = readint();
if(opt == 2)
printf("%.10f\n",ans);
else{
s[++ i] = readint(), average = (s[bro]+s[i])/(bro+1.0);
while(bro+1 < i and (s[bro+1]+s[i])/(bro+2.0) < average)
++ bro, average = (s[bro]+s[i])/(bro+1.0);
getMax(ans,s[i]-average);
s[i] += s[i-1]; // 前缀和
}
}
return 0;
}